1/* Shared library add-on to iptables for DSCP
2 *
3 * (C) 2000- 2002 by Matthew G. Marsh <mgm@paktronix.com>,
4 * 		     Harald Welte <laforge@gnumonks.org>
5 *
6 * This program is distributed under the terms of GNU GPL v2, 1991
7 *
8 * libipt_DSCP.c borrowed heavily from libipt_TOS.c
9 *
10 * --set-class added by Iain Barnes
11 */
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <getopt.h>
16
17#include <iptables.h>
18#include <linux/netfilter_ipv4/ip_tables.h>
19#include <linux/netfilter_ipv4/ipt_DSCP.h>
20
21/* This is evil, but it's my code - HW*/
22#include "libipt_dscp_helper.c"
23
24
25static void init(struct ipt_entry_target *t, unsigned int *nfcache)
26{
27}
28
29static void help(void)
30{
31	printf(
32"DSCP target options\n"
33"  --set-dscp value		Set DSCP field in packet header to value\n"
34"  		                This value can be in decimal (ex: 32)\n"
35"               		or in hex (ex: 0x20)\n"
36"  --set-dscp-class class	Set the DSCP field in packet header to the\n"
37"				value represented by the DiffServ class value.\n"
38"				This class may be EF,BE or any of the CSxx\n"
39"				or AFxx classes.\n"
40"\n"
41"				These two options are mutually exclusive !\n"
42);
43}
44
45static struct option opts[] = {
46	{ "set-dscp", 1, 0, 'F' },
47	{ "set-dscp-class", 1, 0, 'G' },
48	{ 0 }
49};
50
51static void
52parse_dscp(const char *s, struct ipt_DSCP_info *dinfo)
53{
54	unsigned int dscp;
55
56	if (string_to_number(s, 0, 255, &dscp) == -1)
57		exit_error(PARAMETER_PROBLEM,
58			   "Invalid dscp `%s'\n", s);
59
60	if (dscp > IPT_DSCP_MAX)
61		exit_error(PARAMETER_PROBLEM,
62			   "DSCP `%d` out of range\n", dscp);
63
64    	dinfo->dscp = (u_int8_t )dscp;
65    	return;
66}
67
68
69static void
70parse_class(const char *s, struct ipt_DSCP_info *dinfo)
71{
72	unsigned int dscp = class_to_dscp(s);
73
74	/* Assign the value */
75	dinfo->dscp = (u_int8_t)dscp;
76}
77
78
79static int
80parse(int c, char **argv, int invert, unsigned int *flags,
81      const struct ipt_entry *entry,
82      struct ipt_entry_target **target)
83{
84	struct ipt_DSCP_info *dinfo
85		= (struct ipt_DSCP_info *)(*target)->data;
86
87	switch (c) {
88	case 'F':
89		if (*flags)
90			exit_error(PARAMETER_PROBLEM,
91			           "DSCP target: Only use --set-dscp ONCE!");
92		parse_dscp(optarg, dinfo);
93		*flags = 1;
94		break;
95	case 'G':
96		if (*flags)
97			exit_error(PARAMETER_PROBLEM,
98				   "DSCP target: Only use --set-dscp-class ONCE!");
99		parse_class(optarg, dinfo);
100		*flags = 1;
101		break;
102
103	default:
104		return 0;
105	}
106
107	return 1;
108}
109
110static void
111final_check(unsigned int flags)
112{
113	if (!flags)
114		exit_error(PARAMETER_PROBLEM,
115		           "DSCP target: Parameter --set-dscp is required");
116}
117
118static void
119print_dscp(u_int8_t dscp, int numeric)
120{
121 	printf("0x%02x ", dscp);
122}
123
124/* Prints out the targinfo. */
125static void
126print(const struct ipt_ip *ip,
127      const struct ipt_entry_target *target,
128      int numeric)
129{
130	const struct ipt_DSCP_info *dinfo =
131		(const struct ipt_DSCP_info *)target->data;
132	printf("DSCP set ");
133	print_dscp(dinfo->dscp, numeric);
134}
135
136/* Saves the union ipt_targinfo in parsable form to stdout. */
137static void
138save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
139{
140	const struct ipt_DSCP_info *dinfo =
141		(const struct ipt_DSCP_info *)target->data;
142
143	printf("--set-dscp 0x%02x ", dinfo->dscp);
144}
145
146static struct iptables_target dscp = {
147	.next		= NULL,
148	.name		= "DSCP",
149	.version	= IPTABLES_VERSION,
150	.size		= IPT_ALIGN(sizeof(struct ipt_DSCP_info)),
151	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_DSCP_info)),
152	.help		= &help,
153	.init		= &init,
154	.parse		= &parse,
155	.final_check	= &final_check,
156	.print		= &print,
157	.save		= &save,
158	.extra_opts	= opts
159};
160
161void _init(void)
162{
163	register_target(&dscp);
164}
165