ISC DHCP  4.3.5
A reference DHCPv4 and DHCPv6 implementation
tr.c
Go to the documentation of this file.
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"
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
#define ETHERTYPE_IP
Definition: if_ether.h:57
char name[IFNAMSIZ]
Definition: dhcpd.h:1375
ssize_t decode_tr_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
#define MDL
Definition: omapip.h:568
void assemble_tr_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
u_int16_t uh_dport
Definition: udp.h:63
#define IP_HL(iph)
Definition: ip.h:63
int16_t ip_off
Definition: ip.h:52
Definition: udp.h:61
u_int16_t local_port
Definition: dhclient.c:91
#define IP_OFFMASK
Definition: ip.h:55
Definition: ip.h:47
void dfree(void *, const char *, int)
Definition: alloc.c:131
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:56
u_int8_t ip_p
Definition: ip.h:57