summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/pppoe/tr101.c
blob: bb8b845acc475e1ef0e5c6bccdf99f005f4ee7e7 (plain)
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <net/ethernet.h>

#include "triton.h"
#include "ppp.h"
#include "log.h"
#include "radius.h"
#include "memdebug.h"

#include "pppoe.h"

#define OPT_CIRCUIT_ID                0x01
#define OPT_REMOTE_AGENT_ID           0x02
#define OPT_ACTUAL_DATA_RATE_UP       0x81
#define OPT_ACTUAL_DATA_RATE_DOWN     0x82
#define OPT_MIN_DATA_RATE_UP          0x83
#define OPT_MIN_DATA_RATE_DOWN        0x84
#define OPT_ATT_DATA_RATE_UP          0x85
#define OPT_ATT_DATA_RATE_DOWN        0x86
#define OPT_MAX_DATA_RATE_UP          0x87
#define OPT_MAX_DATA_RATE_DOWN        0x88
#define OPT_MIN_DATA_RATE_UP_LP       0x89
#define OPT_MIN_DATA_RATE_DOWN_LP     0x8A
#define OPT_MAX_INTERL_DELAY_UP       0x8B
#define OPT_ACTUAL_INTERL_DELAY_UP    0x8C
#define OPT_MAX_INTER_DELAY_DOWN      0x8D
#define OPT_ACTUAL_INTER_DELAY_DOWN   0x8E
#define ACCESS_LOOP_ENCAP             0x90
#define IFW_SESSION                   0xFE

static int tr101_send_request(struct pppoe_tag *tr101, struct rad_packet_t *pack, int type)
{
	uint8_t *ptr = (uint8_t *)tr101->tag_data + 4;
	uint8_t *endptr = (uint8_t *)tr101->tag_data + ntohs(tr101->tag_len);
	int id, len;
	char str[64];

	while (ptr < endptr) {
		if (ptr + 2 > endptr)
			goto inval;
		id = *ptr++;
		len = *ptr++;
		if (ptr + len > endptr)
			goto inval;

		/* Section 4 of RFC 4679 states that attributes 0x83 to 0x8E
		 * mustn't be included in RADIUS access requests.
		 * This is in contradiction with the TR-101 specification
		 * which excludes attributes 0x85 to 0x90.
		 * Here, we follow the TR-101 guidelines.
		 */
		if (type && id >= 0x85 && id <= 0x90) {
			ptr += len;
			continue;
		}
		switch (id) {
			case OPT_CIRCUIT_ID:
				if (len > 63)
					goto inval;
				memcpy(str, ptr, len);
				str[len] = 0;
				if (rad_packet_add_str(pack, "ADSL-Forum", "ADSL-Agent-Circuit-Id", str))
					return -1;
				break;
			case OPT_REMOTE_AGENT_ID:
				if (len > 63)
					goto inval;
				memcpy(str, ptr, len);
				str[len] = 0;
				if (rad_packet_add_str(pack, "ADSL-Forum", "ADSL-Agent-Remote-Id", str))
					return -1;
				break;
			case OPT_ACTUAL_DATA_RATE_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_ACTUAL_DATA_RATE_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MIN_DATA_RATE_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MIN_DATA_RATE_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_ATT_DATA_RATE_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_ATT_DATA_RATE_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MAX_DATA_RATE_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MAX_DATA_RATE_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MIN_DATA_RATE_UP_LP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream-Low-Power", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MIN_DATA_RATE_DOWN_LP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream-Low-Power", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MAX_INTERL_DELAY_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_ACTUAL_INTERL_DELAY_UP:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Upstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_MAX_INTER_DELAY_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case OPT_ACTUAL_INTER_DELAY_DOWN:
				if (len != 4)
					goto inval;
				if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Downstream", ntohl(*(uint32_t *)ptr)))
					return -1;
				break;
			case ACCESS_LOOP_ENCAP:
				if (len != 3)
					goto inval;
				/* Each byte in this tag represents an
				 * independent field: Data Link, Encaps 1
				 * and Encaps 2.
				 * TR-101 and RFC 4679 aggree on the meaning
				 * of the Encaps 1 and Encaps 2 fields. For
				 * Data Link, TR-101 states that 0 means AAL5
				 * and 1 means Ethernet, while RFC 4679 says
				 * AAL5 is 1 and Ethernet is 2.
				 *
				 * Currently, we build the RADIUS request using
				 * the tag received from PPPoE (TR-101 format).
				 * RFC 4679 format would require conversion.
				 */
				memcpy(str, ptr, 3);
				if (rad_packet_add_octets(pack, "ADSL-Forum", "Access-Loop-Encapsulation", (uint8_t *)str, 3))
					return -1;
				break;
			case IFW_SESSION:
				if (len != 0)
					goto inval;
				if (rad_packet_add_octets(pack, "ADSL-Forum", "IWF-Session", NULL, 0))
					return -1;
				break;
		}
		ptr += len;
	}

	return 0;

inval:
	log_ppp_warn("pppoe:tr101: invalid tag received\n");
	return -1;
}

int tr101_send_access_request(struct pppoe_tag *tr101, struct rad_packet_t *pack)
{
	return tr101_send_request(tr101, pack, 1);
}

int tr101_send_accounting_request(struct pppoe_tag *tr101, struct rad_packet_t *pack)
{
	return tr101_send_request(tr101, pack, 0);
}