3a1cbdfe408cb7d9ccc112891429cb9b6a8459f0
[tinc] / src / route.c
1 /*
2     route.c -- routing
3     Copyright (C) 2000-2002 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2002 Guus Sliepen <guus@sliepen.eu.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: route.c,v 1.1.2.52 2003/07/06 17:15:25 guus Exp $
21 */
22
23 #include "config.h"
24
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
27 #endif
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #ifdef HAVE_NET_IF_H
31 #include <net/if.h>
32 #endif
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
35 #endif
36 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
38 #endif
39 #include <netinet/ip.h>
40 #include <netinet/ip_icmp.h>
41 #include <netinet/ip6.h>
42 #include <netinet/icmp6.h>
43 #include <netinet/if_ether.h>
44 #include <utils.h>
45 #include <xalloc.h>
46 #include <syslog.h>
47 #include <string.h>
48 #ifdef HAVE_INTTYPES_H
49 #include <inttypes.h>
50 #endif
51
52 #include <avl_tree.h>
53
54 #include "net.h"
55 #include "connection.h"
56 #include "subnet.h"
57 #include "route.h"
58 #include "protocol.h"
59 #include "device.h"
60
61 #include "system.h"
62
63 /* Missing definitions */
64
65 #ifndef ETHER_ADDR_LEN
66 #define ETHER_ADDR_LEN 6
67 #endif
68
69 #ifndef ICMP_DEST_UNREACH
70 #define ICMP_DEST_UNREACH 3
71 #endif
72
73 #ifndef ICMP_NET_UNKNOWN
74 #define ICMP_NET_UNKNOWN 6
75 #endif
76
77 #ifndef ICMP_NET_UNREACH
78 #define ICMP_NET_UNREACH 0
79 #endif
80
81 int routing_mode = RMODE_ROUTER;
82 int priorityinheritance = 0;
83 int macexpire = 600;
84 int overwrite_mac = 0;
85 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
86
87 /* RFC 1071 */
88
89 uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
90 {
91         uint16_t *p = data;
92         uint32_t checksum = prevsum ^ 0xFFFF;
93
94         while(len >= 2) {
95                 checksum += *p++;
96                 len -= 2;
97         }
98         
99         if(len)
100                 checksum += *(unsigned char *)p;
101
102         while(checksum >> 16)
103                 checksum = (checksum & 0xFFFF) + (checksum >> 16);
104
105         return ~checksum;
106 }
107
108 int ratelimit(void) {
109         static time_t lasttime = 0;
110         
111         if(lasttime == now)
112                 return 1;
113
114         lasttime = now;
115         return 0;
116 }
117         
118 void learn_mac(mac_t *address)
119 {
120         subnet_t *subnet;
121         avl_node_t *node;
122         connection_t *c;
123
124         cp();
125
126         subnet = lookup_subnet_mac(address);
127
128         /* If we don't know this MAC address yet, store it */
129
130         if(!subnet || subnet->owner != myself) {
131                 if(debug_lvl >= DEBUG_TRAFFIC)
132                         syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
133                                    address->x[0], address->x[1], address->x[2], address->x[3],
134                                    address->x[4], address->x[5]);
135
136                 subnet = new_subnet();
137                 subnet->type = SUBNET_MAC;
138                 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
139                 subnet_add(myself, subnet);
140
141                 /* And tell all other tinc daemons it's our MAC */
142
143                 for(node = connection_tree->head; node; node = node->next) {
144                         c = (connection_t *) node->data;
145                         if(c->status.active)
146                                 send_add_subnet(c, subnet);
147                 }
148         }
149
150         subnet->net.mac.lastseen = now;
151 }
152
153 void age_mac(void)
154 {
155         subnet_t *s;
156         connection_t *c;
157         avl_node_t *node, *next, *node2;
158
159         cp();
160
161         for(node = myself->subnet_tree->head; node; node = next) {
162                 next = node->next;
163                 s = (subnet_t *) node->data;
164                 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
165                         if(debug_lvl >= DEBUG_TRAFFIC)
166                                 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
167                                            s->net.mac.address.x[0], s->net.mac.address.x[1],
168                                            s->net.mac.address.x[2], s->net.mac.address.x[3],
169                                            s->net.mac.address.x[4], s->net.mac.address.x[5]);
170
171                         for(node2 = connection_tree->head; node2; node2 = node2->next) {
172                                 c = (connection_t *) node2->data;
173                                 if(c->status.active)
174                                         send_del_subnet(c, s);
175                         }
176
177                         subnet_del(myself, s);
178                 }
179         }
180 }
181
182 node_t *route_mac(vpn_packet_t *packet)
183 {
184         subnet_t *subnet;
185
186         cp();
187
188         /* Learn source address */
189
190         learn_mac((mac_t *)(&packet->data[6]));
191
192         /* Lookup destination address */
193
194         subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
195
196         if(subnet)
197                 return subnet->owner;
198         else
199                 return NULL;
200 }
201
202 /* RFC 792 */
203
204 void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
205 {
206         struct ip *hdr;
207         struct icmp *icmp;
208         
209         struct in_addr ip_src;
210         struct in_addr ip_dst;
211         uint32_t oldlen;
212
213         if(ratelimit())
214                 return;
215         
216         cp();
217
218         hdr = (struct ip *)(packet->data + 14);
219         icmp = (struct icmp *)(packet->data + 14 + 20);
220
221         /* Remember original source and destination */
222                 
223         memcpy(&ip_src, &hdr->ip_src, 4);
224         memcpy(&ip_dst, &hdr->ip_dst, 4);
225         oldlen = packet->len - 14;
226         
227         if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
228                 oldlen = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
229         
230         /* Copy first part of original contents to ICMP message */
231         
232         memmove(&icmp->icmp_ip, hdr, oldlen);
233
234         /* Fill in IPv4 header */
235         
236         hdr->ip_v = 4;
237         hdr->ip_hl = sizeof(*hdr) / 4;
238         hdr->ip_tos = 0;
239         hdr->ip_len = htons(20 + 8 + oldlen);
240         hdr->ip_id = 0;
241         hdr->ip_off = 0;
242         hdr->ip_ttl = 255;
243         hdr->ip_p = IPPROTO_ICMP;
244         hdr->ip_sum = 0;
245         memcpy(&hdr->ip_src, &ip_dst, 4);
246         memcpy(&hdr->ip_dst, &ip_src, 4);
247
248         hdr->ip_sum = inet_checksum(hdr, 20, ~0);
249         
250         /* Fill in ICMP header */
251         
252         icmp->icmp_type = ICMP_DEST_UNREACH;
253         icmp->icmp_code = code;
254         icmp->icmp_cksum = 0;
255         
256         icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
257         
258         packet->len = 14 + 20 + 8 + oldlen;
259         
260         write_packet(packet);
261 }
262
263 node_t *route_ipv4(vpn_packet_t *packet)
264 {
265         subnet_t *subnet;
266
267         cp();
268
269         if(priorityinheritance)
270                 packet->priority = packet->data[15];
271
272         subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
273
274         if(!subnet) {
275                 if(debug_lvl >= DEBUG_TRAFFIC) {
276                         syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
277                                    packet->data[30], packet->data[31], packet->data[32],
278                                    packet->data[33]);
279                 }
280
281                 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
282                 return NULL;
283         }
284         
285         if(!subnet->owner->status.reachable)
286                 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
287
288         return subnet->owner;
289 }
290
291 /* RFC 2463 */
292
293 void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
294 {
295         struct ip6_hdr *hdr;
296         struct icmp6_hdr *icmp;
297         uint16_t checksum;      
298
299         struct {
300                 struct in6_addr ip6_src;        /* source address */
301                 struct in6_addr ip6_dst;        /* destination address */
302                 uint32_t length;
303                 uint32_t next;
304         } pseudo;
305
306         if(ratelimit())
307                 return;
308         
309         cp();
310
311         hdr = (struct ip6_hdr *)(packet->data + 14);
312         icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
313
314         /* Remember original source and destination */
315                 
316         memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
317         memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
318         pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
319         
320         if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
321                 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
322         
323         /* Copy first part of original contents to ICMP message */
324         
325         memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
326
327         /* Fill in IPv6 header */
328         
329         hdr->ip6_flow = htonl(0x60000000UL);
330         hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
331         hdr->ip6_nxt = IPPROTO_ICMPV6;
332         hdr->ip6_hlim = 255;
333         memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
334         memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
335
336         /* Fill in ICMP header */
337         
338         icmp->icmp6_type = ICMP6_DST_UNREACH;
339         icmp->icmp6_code = code;
340         icmp->icmp6_cksum = 0;
341
342         /* Create pseudo header */
343                 
344         pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
345         pseudo.next = htonl(IPPROTO_ICMPV6);
346
347         /* Generate checksum */
348         
349         checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
350         checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
351
352         icmp->icmp6_cksum = checksum;
353         
354         packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
355         
356         write_packet(packet);
357 }
358
359 node_t *route_ipv6(vpn_packet_t *packet)
360 {
361         subnet_t *subnet;
362
363         cp();
364
365         subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
366
367         if(!subnet) {
368                 if(debug_lvl >= DEBUG_TRAFFIC) {
369                         syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
370                                    ntohs(*(uint16_t *) & packet->data[38]),
371                                    ntohs(*(uint16_t *) & packet->data[40]),
372                                    ntohs(*(uint16_t *) & packet->data[42]),
373                                    ntohs(*(uint16_t *) & packet->data[44]),
374                                    ntohs(*(uint16_t *) & packet->data[46]),
375                                    ntohs(*(uint16_t *) & packet->data[48]),
376                                    ntohs(*(uint16_t *) & packet->data[50]),
377                                    ntohs(*(uint16_t *) & packet->data[52]));
378                 }
379                 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
380
381                 return NULL;
382         }
383
384         if(!subnet->owner->status.reachable)
385                 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
386
387         return subnet->owner;
388 }
389
390 /* RFC 2461 */
391
392 void route_neighborsol(vpn_packet_t *packet)
393 {
394         struct ip6_hdr *hdr;
395         struct nd_neighbor_solicit *ns;
396         struct nd_opt_hdr *opt;
397         subnet_t *subnet;
398         uint16_t checksum;
399
400         struct {
401                 struct in6_addr ip6_src;        /* source address */
402                 struct in6_addr ip6_dst;        /* destination address */
403                 uint32_t length;
404                 uint32_t next;
405         } pseudo;
406
407         cp();
408
409         hdr = (struct ip6_hdr *)(packet->data + 14);
410         ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
411         opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
412
413         /* First, snatch the source address from the neighbor solicitation packet */
414
415         if(overwrite_mac)
416                 memcpy(mymac.x, packet->data + 6, 6);
417
418         /* Check if this is a valid neighbor solicitation request */
419
420         if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
421            opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
422                 if(debug_lvl > DEBUG_TRAFFIC) {
423                         syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
424                 }
425                 return;
426         }
427
428         /* Create pseudo header */
429
430         memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
431         memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
432         pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
433         pseudo.next = htonl(IPPROTO_ICMPV6);
434
435         /* Generate checksum */
436
437         checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
438         checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
439
440         if(checksum) {
441                 if(debug_lvl >= DEBUG_TRAFFIC)
442                         syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
443                 return;
444         }
445
446         /* Check if the IPv6 address exists on the VPN */
447
448         subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
449
450         if(!subnet) {
451                 if(debug_lvl >= DEBUG_TRAFFIC) {
452                         syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
453                                    ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
454                                    ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
455                                    ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
456                                    ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
457                                    ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
458                                    ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
459                                    ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
460                                    ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
461                 }
462
463                 return;
464         }
465
466         /* Check if it is for our own subnet */
467
468         if(subnet->owner == myself)
469                 return;                                 /* silently ignore */
470
471         /* Create neighbor advertation reply */
472
473         memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* copy destination address */
474         packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF;   /* mangle source address so it looks like it's not from us */
475
476         memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16);       /* swap destination and source protocol address */
477         memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16);   /* ... */
478
479         memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6);  /* add fake source hard addr */
480
481         ns->nd_ns_hdr.icmp6_cksum = 0;
482         ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
483         ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40;    /* Set solicited flag */
484         ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
485                 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
486                 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
487         opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
488
489         /* Create pseudo header */
490
491         memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
492         memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
493         pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
494         pseudo.next = htonl(IPPROTO_ICMPV6);
495
496         /* Generate checksum */
497
498         checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
499         checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
500
501         ns->nd_ns_hdr.icmp6_cksum = checksum;
502
503         write_packet(packet);
504 }
505
506 /* RFC 826 */
507
508 void route_arp(vpn_packet_t *packet)
509 {
510         struct ether_arp *arp;
511         subnet_t *subnet;
512         uint8_t ipbuf[4];
513
514         cp();
515
516         /* First, snatch the source address from the ARP packet */
517
518         if(overwrite_mac)
519                 memcpy(mymac.x, packet->data + 6, 6);
520
521         /* This routine generates replies to ARP requests.
522            You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
523            Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
524          */
525
526         arp = (struct ether_arp *)(packet->data + 14);
527
528         /* Check if this is a valid ARP request */
529
530         if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
531            arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
532                 if(debug_lvl > DEBUG_TRAFFIC) {
533                         syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
534                 }
535                 return;
536         }
537
538         /* Check if the IPv4 address exists on the VPN */
539
540         subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
541
542         if(!subnet) {
543                 if(debug_lvl >= DEBUG_TRAFFIC) {
544                         syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
545                                    arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
546                                    arp->arp_tpa[3]);
547                 }
548
549                 return;
550         }
551
552         /* Check if it is for our own subnet */
553
554         if(subnet->owner == myself)
555                 return;                                 /* silently ignore */
556
557         memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* copy destination address */
558         packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF;   /* mangle source address so it looks like it's not from us */
559
560         memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
561         memcpy(arp->arp_tpa, arp->arp_spa, 4);  /* swap destination and source protocol address */
562         memcpy(arp->arp_spa, ipbuf, 4); /* ... */
563
564         memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
565         memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* add fake source hard addr */
566         arp->arp_op = htons(ARPOP_REPLY);
567
568         write_packet(packet);
569 }
570
571 void route_outgoing(vpn_packet_t *packet)
572 {
573         uint16_t type;
574         node_t *n = NULL;
575
576         cp();
577
578         /* FIXME: multicast? */
579
580         switch (routing_mode) {
581                 case RMODE_ROUTER:
582                         type = ntohs(*((uint16_t *)(&packet->data[12])));
583                         switch (type) {
584                                 case 0x0800:
585                                         n = route_ipv4(packet);
586                                         break;
587
588                                 case 0x86DD:
589                                         if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
590                                                 route_neighborsol(packet);
591                                                 return;
592                                         }
593                                         n = route_ipv6(packet);
594                                         break;
595
596                                 case 0x0806:
597                                         route_arp(packet);
598                                         return;
599
600                                 default:
601                                         if(debug_lvl >= DEBUG_TRAFFIC)
602                                                 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
603                                         return;
604                         }
605                         if(n)
606                                 send_packet(n, packet);
607                         break;
608
609                 case RMODE_SWITCH:
610                         n = route_mac(packet);
611                         if(n)
612                                 send_packet(n, packet);
613                         else
614                                 broadcast_packet(myself, packet);
615                         break;
616
617                 case RMODE_HUB:
618                         broadcast_packet(myself, packet);
619                         break;
620         }
621 }
622
623 void route_incoming(node_t *source, vpn_packet_t *packet)
624 {
625         switch (routing_mode) {
626                 case RMODE_ROUTER:
627                         {
628                                 node_t *n = NULL;
629                                 uint16_t type;
630
631                                 type = ntohs(*((uint16_t *)(&packet->data[12])));
632                                 switch (type) {
633                                         case 0x0800:
634                                                 n = route_ipv4(packet);
635                                                 break;
636
637                                         case 0x86DD:
638                                                 n = route_ipv6(packet);
639                                                 break;
640
641                                         default:
642                                                 n = myself;
643                                                 break;
644                                 }
645
646                                 if(n) {
647                                         if(n == myself) {
648                                                 if(overwrite_mac)
649                                                         memcpy(packet->data, mymac.x, 6);
650                                                 write_packet(packet);
651                                         } else
652                                                 send_packet(n, packet);
653                                 }
654                         }
655                         break;
656
657                 case RMODE_SWITCH:
658                         {
659                                 subnet_t *subnet;
660
661                                 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
662
663                                 if(subnet) {
664                                         if(subnet->owner == myself)
665                                                 write_packet(packet);
666                                         else
667                                                 send_packet(subnet->owner, packet);
668                                 } else {
669                                         broadcast_packet(source, packet);
670                                         write_packet(packet);
671                                 }
672                         }
673                         break;
674
675                 case RMODE_HUB:
676                         broadcast_packet(source, packet);       /* Spread it on */
677                         write_packet(packet);
678                         break;
679         }
680 }