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