add Cisco-AVPairs to RADIUS accounting records via plugin_radius_account
[l2tpns.git] / autothrottle.c
1 #include <string.h>
2 #include "l2tpns.h"
3 #include "plugin.h"
4
5 /* set up throttling based on RADIUS reply */
6
7 /*
8 * lcp:interface-config#1=service-policy input N
9 * lcp:interface-config#2=service-policy output N
10 *
11 * throttle=N
12 * throttle=yes (use throttle_rate from config)
13 * throttle=no
14 */
15
16 char const *cvs_id = "$Id: autothrottle.c,v 1.16 2005-10-11 09:04:53 bodea Exp $";
17
18 int plugin_api_version = PLUGIN_API_VERSION;
19 static struct pluginfuncs *f = 0;
20
21 #define THROTTLE_KEY "lcp:interface-config"
22
23 int plugin_radius_response(struct param_radius_response *data)
24 {
25 if (!strncmp(data->key, THROTTLE_KEY, sizeof(THROTTLE_KEY) - 1))
26 {
27 char *sp = strchr(data->value, ' ');
28 char type;
29 int rate;
30
31 if (!sp || sp - data->value < 4 ||
32 strncmp("service-policy", data->value, sp - data->value))
33 return PLUGIN_RET_OK;
34
35 while (*sp == ' ') sp++;
36 data->value = sp;
37
38 if (!(sp = strchr(data->value, ' ')) ||
39 (strncmp("input", data->value, sp - data->value) &&
40 strncmp("output", data->value, sp - data->value)))
41 {
42 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
43 " Not throttling user (invalid type %.*s)\n",
44 sp - data->value, data->value);
45
46 return PLUGIN_RET_OK;
47 }
48
49 type = *data->value;
50
51 while (*sp == ' ') sp++;
52 data->value = sp;
53
54 if ((rate = strtol(data->value, &sp, 10)) < 0 || *sp)
55 {
56 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
57 " Not throttling user (invalid rate %s)\n",
58 data->value);
59
60 return PLUGIN_RET_OK;
61 }
62
63 if (type == 'i')
64 {
65 data->s->throttle_in = rate;
66 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
67 " Throttling user input to %dkb/s\n", rate);
68 }
69 else
70 {
71 data->s->throttle_out = rate;
72 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
73 " Throttling user output to %dkb/s\n", rate);
74 }
75 }
76 else if (!strcmp(data->key, "throttle"))
77 {
78 char *e;
79 int rate;
80
81 if ((rate = strtol(data->value, &e, 10)) < 0 || *e)
82 {
83 rate = -1;
84 if (!strcmp(data->value, "yes"))
85 {
86 unsigned long *ts = f->getconfig("throttle_speed", UNSIGNED_LONG);
87 if (ts)
88 rate = *ts;
89 }
90 else if (!strcmp(data->value, "no"))
91 rate = 0;
92 }
93
94 if (rate < 0)
95 return PLUGIN_RET_OK;
96
97 if (rate)
98 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
99 " Throttling user to %dkb/s\n", rate);
100 else
101 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
102 " Not throttling user\n");
103
104 data->s->throttle_in = data->s->throttle_out = rate;
105 }
106
107 return PLUGIN_RET_OK;
108 }
109
110 int plugin_radius_reset(struct param_radius_reset *data)
111 {
112 f->throttle(f->get_id_by_session(data->s), 0, 0);
113 return PLUGIN_RET_OK;
114 }
115
116 int plugin_radius_account(struct param_radius_account *data)
117 {
118 if (data->s->throttle_in || data->s->throttle_out)
119 {
120 uint8_t *p = *data->packet;
121 int i = 1;
122
123 if (data->s->throttle_in)
124 {
125 *p = 26; // vendor-specific
126 *(uint32_t *) (p + 2) = htonl(9); // Cisco
127 p[6] = 1; // Cisco-AVPair
128 p[7] = 2 + sprintf((char *) p + 8,
129 "lcp:interface-config#%d=service-policy input %d", i++,
130 data->s->throttle_in);
131
132 p[1] = p[7] + 6;
133 p += p[1];
134 }
135
136 if (data->s->throttle_out)
137 {
138 *p = 26; // vendor-specific
139 *(uint32_t *) (p + 2) = htonl(9); // Cisco
140 p[6] = 1; // Cisco-AVPair
141 p[7] = 2 + sprintf((char *) p + 8,
142 "lcp:interface-config#%d=service-policy output %d", i++,
143 data->s->throttle_out);
144
145 p[1] = p[7] + 6;
146 p += p[1];
147 }
148
149 *data->packet = p;
150 }
151
152 return PLUGIN_RET_OK;
153 }
154
155 int plugin_init(struct pluginfuncs *funcs)
156 {
157 return ((f = funcs)) ? 1 : 0;
158 }