File: autothrottle.c

package info (click to toggle)
l2tpns 2.3.3-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,840 kB
  • sloc: ansic: 21,992; sh: 164; perl: 139; makefile: 127
file content (158 lines) | stat: -rw-r--r-- 3,617 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <string.h>
#include <netinet/ip6.h>
#include "dhcp6.h"
#include "l2tpns.h"
#include "plugin.h"

/* set up throttling based on RADIUS reply */

/*
 * lcp:interface-config#1=service-policy input N
 * lcp:interface-config#2=service-policy output N
 *
 * throttle=N
 * throttle=yes (use throttle_speed from config)
 * throttle=no
 */

int plugin_api_version = PLUGIN_API_VERSION;
static struct pluginfuncs *f = 0;

#define THROTTLE_KEY "lcp:interface-config"

int plugin_radius_response(struct param_radius_response *data)
{
    if (!strncmp(data->key, THROTTLE_KEY, sizeof(THROTTLE_KEY) - 1))
    {
	char *sp = strchr(data->value, ' ');
	char type;
	int rate;

	if (!sp || sp - data->value < 4 ||
	    strncmp("service-policy", data->value, sp - data->value))
	    return PLUGIN_RET_OK;

	while (*sp == ' ') sp++;
	data->value = sp;

	if (!(sp = strchr(data->value, ' ')) ||
	    (strncmp("input", data->value, sp - data->value) &&
	    strncmp("output", data->value, sp - data->value)))
	{
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		"         Not throttling user (invalid type %.*s)\n",
		sp - data->value, data->value);

	    return PLUGIN_RET_OK;
	}

	type = *data->value;

	while (*sp == ' ') sp++;
	data->value = sp;

	if ((rate = strtol(data->value, &sp, 10)) < 0 || *sp)
	{
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		"         Not throttling user (invalid rate %s)\n",
		data->value);

	    return PLUGIN_RET_OK;
	}

	if (type == 'i')
	{
	    data->s->throttle_in = rate;
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		"         Throttling user input to %dkb/s\n", rate);
	}
	else
	{
	    data->s->throttle_out = rate;
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		    "         Throttling user output to %dkb/s\n", rate);
	}
    }
    else if (!strcmp(data->key, "throttle"))
    {
	char *e;
	int rate;

	if ((rate = strtol(data->value, &e, 10)) < 0 || *e)
	{
	    rate = -1;
	    if (!strcmp(data->value, "yes"))
	    {
		unsigned long *ts = f->getconfig("throttle_speed", UNSIGNED_LONG);
		if (ts)
		    rate = *ts;
	    }
	    else if (!strcmp(data->value, "no"))
		rate = 0;
	}

	if (rate < 0)
	    return PLUGIN_RET_OK;

	if (rate)
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		"         Throttling user to %dkb/s\n", rate);
	else
	    f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
		"         Not throttling user\n");

	data->s->throttle_in = data->s->throttle_out = rate;
    }

    return PLUGIN_RET_OK;
}

int plugin_radius_reset(struct param_radius_reset *data)
{
    f->throttle(f->get_id_by_session(data->s), 0, 0);
    return PLUGIN_RET_OK;
}

int plugin_radius_account(struct param_radius_account *data)
{
    if (data->s->throttle_in || data->s->throttle_out)
    {
	uint8_t *p = *data->packet;
	int i = 1;

	if (data->s->throttle_in)
	{
	    *p = 26;				// vendor-specific
	    *(uint32_t *) (p + 2) = htonl(9);	// Cisco
	    p[6] = 1;				// Cisco-AVPair
	    p[7] = 2 + sprintf((char *) p + 8,
		"lcp:interface-config#%d=service-policy input %d", i++,
		data->s->throttle_in);

	    p[1] = p[7] + 6;
	    p += p[1];
	}

	if (data->s->throttle_out)
	{
	    *p = 26;				// vendor-specific
	    *(uint32_t *) (p + 2) = htonl(9);	// Cisco
	    p[6] = 1;				// Cisco-AVPair
	    p[7] = 2 + sprintf((char *) p + 8,
		"lcp:interface-config#%d=service-policy output %d", i++,
		data->s->throttle_out);

	    p[1] = p[7] + 6;
	    p += p[1];
	}

	*data->packet = p;
    }

    return PLUGIN_RET_OK;
}

int plugin_init(struct pluginfuncs *funcs)
{
    return ((f = funcs)) ? 1 : 0;
}