1 /* tr.c
2
3 token ring interface support
4 Contributed in May of 1999 by Andrew Chittenden */
5
6 /*
7 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
9 *
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/.
13 *
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.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
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
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);
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];
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 */
60 };
61
62 static struct routing_entry *routing_info = NULL;
63
64 static int routing_timeout = 10;
65 static struct timeval routing_timer;
66
assemble_tr_header(interface,buf,bufix,to)67 void assemble_tr_header (interface, buf, bufix, to)
68 struct interface_info *interface;
69 unsigned char *buf;
70 unsigned *bufix;
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];
80 if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr))
81 memcpy (trh->saddr, &interface -> hw_address.hbuf [1],
82 sizeof (trh->saddr));
83 else
84 memset (trh->saddr, 0x00, sizeof (trh->saddr));
85
86 if (to && to -> hlen == 7) /* XXX */
87 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
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 */
decode_tr_header(interface,buf,bufix,from)120 ssize_t decode_tr_header (interface, buf, bufix, from)
121 struct interface_info *interface;
122 unsigned char *buf;
123 unsigned bufix;
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);
169 udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
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
176 || (ntohs (ip->ip_off) & IP_OFFMASK) != 0
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 */
insert_source_routing(trh,interface)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) {
215 u_int16_t rcf = rover->rcf;
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 */
save_source_routing(trh,interface)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];
252 u_int16_t rcf = 0;
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) {
267 if ((trh->saddr[0] & TR_RII) &&
268 ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
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 */
279 rover = dmalloc (sizeof (struct routing_entry), MDL);
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 */
expire_routes()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;
320 dfree (rover, MDL);
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
331