ISC DHCP  4.4.2b1
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) 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"
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 
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  */
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  */
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  */
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  */
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
#define ETHERTYPE_IP
Definition: if_ether.h:57
char name[IFNAMSIZ]
Definition: dhcpd.h:1403
ssize_t decode_tr_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
#define MDL
Definition: omapip.h:567
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:96
#define IP_OFFMASK
Definition: ip.h:55
Definition: ip.h:47
void dfree(void *, const char *, int)
Definition: alloc.c:145
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
u_int8_t ip_p
Definition: ip.h:57