]>
Commit | Line | Data |
---|---|---|
49733f31 TL |
1 | /* tr.c |
2 | ||
3 | token ring interface support | |
4 | Contributed in May of 1999 by Andrew Chittenden */ | |
0c699a23 TL |
5 | |
6 | /* | |
7512d88b | 7 | * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 8 | * Copyright (c) 1996-2003 by Internet Software Consortium |
0c699a23 | 9 | * |
7512d88b TM |
10 | * This Source Code Form is subject to the terms of the Mozilla Public |
11 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
12 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
0c699a23 | 13 | * |
98311e4b DH |
14 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
19 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
0c699a23 | 21 | * |
98311e4b DH |
22 | * Internet Systems Consortium, Inc. |
23 | * 950 Charter Street | |
24 | * Redwood City, CA 94063 | |
25 | * <info@isc.org> | |
2c85ac9b | 26 | * https://www.isc.org/ |
0c699a23 TL |
27 | */ |
28 | ||
29 | #include "dhcpd.h" | |
30 | ||
31 | #if defined (HAVE_TR_SUPPORT) && \ | |
32 | (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)) | |
33 | #include "includes/netinet/ip.h" | |
34 | #include "includes/netinet/udp.h" | |
35 | #include "includes/netinet/if_ether.h" | |
36 | #include "netinet/if_tr.h" | |
37 | #include <sys/time.h> | |
38 | ||
39 | /* | |
40 | * token ring device handling subroutines. These are required as token-ring | |
41 | * does not have a simple on-the-wire header but requires the use of | |
42 | * source routing | |
43 | */ | |
44 | ||
a34feb7d TM |
45 | static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface); |
46 | static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface); | |
47 | static void expire_routes (void); | |
0c699a23 TL |
48 | |
49 | /* | |
50 | * As we keep a list of interesting routing information only, a singly | |
51 | * linked list is all we need | |
52 | */ | |
53 | struct routing_entry { | |
54 | struct routing_entry *next; | |
55 | unsigned char addr[TR_ALEN]; | |
56 | unsigned char iface[5]; | |
83c0372e EH |
57 | u_int16_t rcf; /* route control field */ |
58 | u_int16_t rseg[8]; /* routing registers */ | |
59 | unsigned long access_time; /* time we last used this entry */ | |
0c699a23 TL |
60 | }; |
61 | ||
62 | static struct routing_entry *routing_info = NULL; | |
63 | ||
64 | static int routing_timeout = 10; | |
65 | static struct timeval routing_timer; | |
66 | ||
67 | void assemble_tr_header (interface, buf, bufix, to) | |
68 | struct interface_info *interface; | |
69 | unsigned char *buf; | |
b1b7b521 | 70 | unsigned *bufix; |
0c699a23 TL |
71 | struct hardware *to; |
72 | { | |
73 | struct trh_hdr *trh; | |
74 | int hdr_len; | |
75 | struct trllc *llc; | |
76 | ||
77 | ||
78 | /* set up the token header */ | |
79 | trh = (struct trh_hdr *) &buf[*bufix]; | |
d98be47b TL |
80 | if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr)) |
81 | memcpy (trh->saddr, &interface -> hw_address.hbuf [1], | |
0c699a23 TL |
82 | sizeof (trh->saddr)); |
83 | else | |
84 | memset (trh->saddr, 0x00, sizeof (trh->saddr)); | |
85 | ||
d98be47b TL |
86 | if (to && to -> hlen == 7) /* XXX */ |
87 | memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr); | |
0c699a23 TL |
88 | else |
89 | memset (trh->daddr, 0xff, sizeof (trh->daddr)); | |
90 | ||
91 | hdr_len = insert_source_routing (trh, interface); | |
92 | ||
93 | trh->ac = AC; | |
94 | trh->fc = LLC_FRAME; | |
95 | ||
96 | /* set up the llc header for snap encoding after the tr header */ | |
97 | llc = (struct trllc *)(buf + *bufix + hdr_len); | |
98 | llc->dsap = EXTENDED_SAP; | |
99 | llc->ssap = EXTENDED_SAP; | |
100 | llc->llc = UI_CMD; | |
101 | llc->protid[0] = 0; | |
102 | llc->protid[1] = 0; | |
103 | llc->protid[2] = 0; | |
104 | llc->ethertype = htons(ETHERTYPE_IP); | |
105 | ||
106 | hdr_len += sizeof(struct trllc); | |
107 | ||
108 | *bufix += hdr_len; | |
109 | } | |
110 | ||
111 | ||
112 | static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | |
113 | ||
114 | /* | |
115 | * decoding the token header is a bit complex as you can see here. It is | |
116 | * further complicated by the linux kernel stripping off some valuable | |
117 | * information (see comment below) even though we've asked for the raw | |
118 | * packets. | |
119 | */ | |
120 | ssize_t decode_tr_header (interface, buf, bufix, from) | |
121 | struct interface_info *interface; | |
122 | unsigned char *buf; | |
b1b7b521 | 123 | unsigned bufix; |
0c699a23 TL |
124 | struct hardware *from; |
125 | { | |
126 | struct trh_hdr *trh = (struct trh_hdr *) buf + bufix; | |
127 | struct trllc *llc; | |
128 | struct ip *ip; | |
129 | struct udphdr *udp; | |
130 | unsigned int route_len = 0; | |
131 | ssize_t hdr_len; | |
132 | struct timeval now; | |
133 | ||
134 | /* see whether any source routing information has expired */ | |
135 | gettimeofday(&now, NULL); | |
136 | ||
137 | if (routing_timer.tv_sec == 0) | |
138 | routing_timer.tv_sec = now.tv_sec + routing_timeout; | |
139 | else if ((now.tv_sec - routing_timer.tv_sec) > 0) | |
140 | expire_routes(); | |
141 | ||
142 | /* the kernel might have stripped off the source | |
143 | * routing bit. We try a heuristic to determine whether | |
144 | * this is the case and put it back on if so | |
145 | */ | |
146 | route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; | |
147 | llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len); | |
148 | if (llc->dsap == EXTENDED_SAP | |
149 | && llc->ssap == EXTENDED_SAP | |
150 | && llc->llc == UI_CMD | |
151 | && llc->protid[0] == 0 | |
152 | && llc->protid[1] == 0 | |
153 | && llc->protid[2] == 0) { | |
154 | /* say there is source routing information present */ | |
155 | trh->saddr[0] |= TR_RII; | |
156 | } | |
157 | ||
158 | if (trh->saddr[0] & TR_RII) | |
159 | route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; | |
160 | else | |
161 | route_len = 0; | |
162 | ||
163 | hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; | |
164 | ||
165 | /* now filter out unwanted packets: this is based on the packet | |
166 | * filter code in bpf.c */ | |
167 | llc = (struct trllc *)(buf + bufix + hdr_len); | |
168 | ip = (struct ip *) (llc + 1); | |
11515e7a | 169 | udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip)); |
0c699a23 TL |
170 | |
171 | /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent | |
172 | * to our port */ | |
173 | if (llc->dsap != EXTENDED_SAP | |
174 | || ntohs(llc->ethertype) != ETHERTYPE_IP | |
175 | || ip->ip_p != IPPROTO_UDP | |
a010c3ff | 176 | || (ntohs (ip->ip_off) & IP_OFFMASK) != 0 |
0c699a23 TL |
177 | || udp->uh_dport != local_port) |
178 | return -1; | |
179 | ||
180 | /* only save source routing information for packets from valued hosts */ | |
181 | save_source_routing(trh, interface); | |
182 | ||
183 | return hdr_len + sizeof (struct trllc); | |
184 | } | |
185 | ||
186 | /* insert_source_routing inserts source route information into the token ring | |
187 | * header | |
188 | */ | |
189 | static int insert_source_routing (trh, interface) | |
190 | struct trh_hdr *trh; | |
191 | struct interface_info* interface; | |
192 | { | |
193 | struct routing_entry *rover; | |
194 | struct timeval now; | |
195 | unsigned int route_len = 0; | |
196 | ||
197 | gettimeofday(&now, NULL); | |
198 | ||
199 | /* single route broadcasts as per rfc 1042 */ | |
200 | if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) { | |
201 | trh->saddr[0] |= TR_RII; | |
202 | trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; | |
203 | trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); | |
204 | trh->rcf = htons(trh->rcf); | |
205 | } else { | |
206 | /* look for a routing entry */ | |
207 | for (rover = routing_info; rover != NULL; rover = rover->next) { | |
208 | if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0) | |
209 | break; | |
210 | } | |
211 | ||
212 | if (rover != NULL) { | |
213 | /* success: route that frame */ | |
214 | if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) { | |
88cd8aca | 215 | u_int16_t rcf = rover->rcf; |
0c699a23 TL |
216 | memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg)); |
217 | rcf ^= TR_RCF_DIR_BIT; | |
218 | rcf &= ~TR_RCF_BROADCAST_MASK; | |
219 | trh->rcf = htons(rcf); | |
220 | trh->saddr[0] |= TR_RII; | |
221 | } | |
222 | rover->access_time = now.tv_sec; | |
223 | } else { | |
224 | /* we don't have any routing information so send a | |
225 | * limited broadcast */ | |
226 | trh->saddr[0] |= TR_RII; | |
227 | trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; | |
228 | trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); | |
229 | trh->rcf = htons(trh->rcf); | |
230 | } | |
231 | } | |
232 | ||
233 | /* return how much of the header we've actually used */ | |
234 | if (trh->saddr[0] & TR_RII) | |
235 | route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; | |
236 | else | |
237 | route_len = 0; | |
238 | ||
239 | return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; | |
240 | } | |
241 | ||
242 | /* | |
243 | * save any source routing information | |
244 | */ | |
245 | static void save_source_routing(trh, interface) | |
246 | struct trh_hdr *trh; | |
247 | struct interface_info *interface; | |
248 | { | |
249 | struct routing_entry *rover; | |
250 | struct timeval now; | |
251 | unsigned char saddr[TR_ALEN]; | |
88cd8aca | 252 | u_int16_t rcf = 0; |
0c699a23 TL |
253 | |
254 | gettimeofday(&now, NULL); | |
255 | ||
256 | memcpy(saddr, trh->saddr, sizeof(saddr)); | |
257 | saddr[0] &= 0x7f; /* strip off source routing present flag */ | |
258 | ||
259 | /* scan our table to see if we've got it */ | |
260 | for (rover = routing_info; rover != NULL; rover = rover->next) { | |
261 | if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0) | |
262 | break; | |
263 | } | |
264 | ||
265 | /* found an entry so update it with fresh information */ | |
266 | if (rover != NULL) { | |
53029a93 TL |
267 | if ((trh->saddr[0] & TR_RII) && |
268 | ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { | |
0c699a23 TL |
269 | rcf = ntohs(trh->rcf); |
270 | rcf &= ~TR_RCF_BROADCAST_MASK; | |
271 | memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); | |
272 | } | |
273 | rover->rcf = rcf; | |
274 | rover->access_time = now.tv_sec; | |
275 | return; /* that's all folks */ | |
276 | } | |
277 | ||
278 | /* no entry found, so create one */ | |
d98be47b | 279 | rover = dmalloc (sizeof (struct routing_entry), MDL); |
0c699a23 TL |
280 | if (rover == NULL) { |
281 | fprintf(stderr, | |
282 | "%s: unable to save source routing information\n", | |
283 | __FILE__); | |
284 | return; | |
285 | } | |
286 | ||
287 | memcpy(rover->addr, saddr, sizeof(rover->addr)); | |
288 | memcpy(rover->iface, interface->name, 5); | |
289 | rover->access_time = now.tv_sec; | |
290 | if (trh->saddr[0] & TR_RII) { | |
291 | if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { | |
292 | rcf = ntohs(trh->rcf); | |
293 | rcf &= ~TR_RCF_BROADCAST_MASK; | |
294 | memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); | |
295 | } | |
296 | rover->rcf = rcf; | |
297 | } | |
298 | ||
299 | /* insert into list */ | |
300 | rover->next = routing_info; | |
301 | routing_info = rover; | |
302 | ||
303 | return; | |
304 | } | |
305 | ||
306 | /* | |
307 | * get rid of old routes | |
308 | */ | |
309 | static void expire_routes() | |
310 | { | |
311 | struct routing_entry *rover; | |
312 | struct routing_entry **prover = &routing_info; | |
313 | struct timeval now; | |
314 | ||
315 | gettimeofday(&now, NULL); | |
316 | ||
317 | while((rover = *prover) != NULL) { | |
318 | if ((now.tv_sec - rover->access_time) > routing_timeout) { | |
319 | *prover = rover->next; | |
d98be47b | 320 | dfree (rover, MDL); |
0c699a23 TL |
321 | } else |
322 | prover = &rover->next; | |
323 | } | |
324 | ||
325 | /* Reset the timer */ | |
326 | routing_timer.tv_sec = now.tv_sec + routing_timeout; | |
327 | routing_timer.tv_usec = now.tv_usec; | |
328 | } | |
329 | ||
330 | #endif |