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