Merge commit 'origin/trunk@12184' into fedora
[iptables.git] / trunk / extensions / tos_values.c
diff --git a/trunk/extensions/tos_values.c b/trunk/extensions/tos_values.c
new file mode 100644 (file)
index 0000000..1630834
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+struct tos_value_mask {
+       uint8_t value, mask;
+};
+
+static const struct tos_symbol_info {
+       unsigned char value;
+       const char *name;
+} tos_symbol_names[] = {
+       {IPTOS_LOWDELAY,    "Minimize-Delay"},
+       {IPTOS_THROUGHPUT,  "Maximize-Throughput"},
+       {IPTOS_RELIABILITY, "Maximize-Reliability"},
+       {IPTOS_MINCOST,     "Minimize-Cost"},
+       {IPTOS_NORMALSVC,   "Normal-Service"},
+       { .name = NULL }
+};
+
+/*
+ * tos_parse_numeric - parse sth. like "15/255"
+ *
+ * @s:         input string
+ * @info:      accompanying structure
+ * @bits:      number of bits that are allowed
+ *             (8 for IPv4 TOS field, 4 for IPv6 Priority Field)
+ */
+static bool tos_parse_numeric(const char *str, struct tos_value_mask *tvm,
+                              unsigned int bits)
+{
+       const unsigned int max = (1 << bits) - 1;
+       unsigned int value;
+       char *end;
+
+       strtonum(str, &end, &value, 0, max);
+       tvm->value = value;
+       tvm->mask  = max;
+
+       if (*end == '/') {
+               const char *p = end + 1;
+
+               if (!strtonum(p, &end, &value, 0, max))
+                       exit_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"",
+                                  str);
+               tvm->mask = value;
+       }
+
+       if (*end != '\0')
+               exit_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str);
+       return true;
+}
+
+static bool tos_parse_symbolic(const char *str, struct tos_value_mask *tvm,
+    unsigned int def_mask)
+{
+       const unsigned int max = 255;
+       const struct tos_symbol_info *symbol;
+
+       if (strtonum(str, NULL, NULL, 0, max))
+               return tos_parse_numeric(str, tvm, max);
+
+       /* Do not consider ECN bits */
+       tvm->mask = def_mask;
+       for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+               if (strcasecmp(str, symbol->name) == 0) {
+                       tvm->value = symbol->value;
+                       return true;
+               }
+
+       exit_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown", str);
+       return false;
+}
+
+static bool tos_try_print_symbolic(const char *prefix,
+    u_int8_t value, u_int8_t mask)
+{
+       const struct tos_symbol_info *symbol;
+
+       if (mask != 0x3F)
+               return false;
+
+       for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+               if (value == symbol->value) {
+                       printf("%s%s ", prefix, symbol->name);
+                       return true;
+               }
+
+       return false;
+}