]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/ddp_rtmptable.c
933c07649ca45ecb75b7a570d77d930f13ae8c31
[apple/xnu.git] / bsd / netat / ddp_rtmptable.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*----------------------------------------------------------------------------
23 *
24 * RTMP & ZIP routing tables access routines
25 *
26 * This code implement b-tree search and manipulation of
27 * of the RTMP routing table and ZIP zone table.
28 *
29 * The RTMP routing table is a data block divided in several routing
30 * entries sorted during insertion in a b-tree form. We use a table and
31 * not dynamically allocated entries because it allow us to scan the whole
32 * table when RTMP packets are generated. The routing table entries are sorted
33 * by there NetStop value (because non extended nets have a NetStart value of
34 * zero. From any point in the tree, the left side contains Network ranges
35 * smaller or equal to the current Node, and the right tree points to higher
36 * values network ranges.
37 *
38 *
39 * 0.01 3/16/94 LD Creation
40 * Modified for MP, 1996 by Tuyen Nguyen
41 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
42 *
43 *----------------------------------------------------------------------------
44 *
45 * Copyright (c) 1994, 1996, 1997, 1998 Apple Computer, Inc.
46 */
47
48 #include <sys/errno.h>
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <machine/spl.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/proc.h>
55 #include <sys/filedesc.h>
56 #include <sys/fcntl.h>
57 #include <sys/mbuf.h>
58 #include <sys/ioctl.h>
59 #include <sys/malloc.h>
60 #include <sys/socket.h>
61 #include <sys/socketvar.h>
62
63 #include <net/if.h>
64 #include <net/if_types.h>
65
66 #include <netat/sysglue.h>
67 #include <netat/appletalk.h>
68 #include <netat/at_var.h>
69 #include <netat/ddp.h>
70 #include <netat/rtmp.h>
71 #include <netat/at_pcb.h>
72 #include <netat/zip.h>
73 #include <netat/routing_tables.h>
74 #include <netat/at_snmp.h>
75 #include <netat/debug.h>
76
77 RT_entry *RT_table_freelist; /* start of free entry list */
78 RT_entry RT_table_start; /* start of the actual entry table */
79 RT_entry *RT_table; /* the routing table */
80 ZT_entry *ZT_table; /* the Zone Information Protocol table */
81 short RT_maxentry; /* Number of entry in RTMP table */
82 short ZT_maxentry; /* Number of entry in ZIP table */
83
84 char errstr[512]; /* used to display meaningfull router errors*/
85
86 extern at_ifaddr_t *ifID_table[];
87 extern at_ifaddr_t *ifID_home;
88 extern snmpStats_t snmpStats;
89
90 short ErrorRTMPoverflow = 0; /* flag if RTMP table is too small for this net */
91 short ErrorZIPoverflow = 0; /* flag if ZIP table is too small for this net */
92
93 /* prototypes */
94 void getIfUsage( int, at_ifnames_t *);
95
96 /*
97 * This a temporary function : just to display the router error
98 */
99
100 void RouterError(port, err_number)
101 short port, err_number;
102
103 {
104 switch (err_number) {
105
106 case ERTR_SEED_CONFLICT:
107 dPrintf(D_M_RTMP, D_L_ERROR,
108 ("**** RTR Error on port# %d SEED_CONFLICT\n", port));
109 break;
110
111 case ERTR_CABLE_CONFLICT:
112 dPrintf(D_M_RTMP, D_L_ERROR,
113 ("**** RTR Error on port# %d CABLE_CONFLICT\n", port));
114 break;
115
116 case ERTR_RTMP_BAD_VERSION:
117 dPrintf(D_M_RTMP, D_L_ERROR,
118 ("**** RTR Error on port# %d RTMP_BAD_VERSION\n", port));
119 break;
120
121 case ERTR_CABLE_STARTUP:
122 dPrintf(D_M_RTMP, D_L_ERROR,
123 ("**** RTR Error on port# %d RTMP_CABLE_STARTUP\n",
124 port));
125 break;
126
127 default:
128 dPrintf(D_M_RTMP, D_L_ERROR,
129 ("**** RTR Error on port# %d WHAT IN THE WORLD IS THIS ONE? code=%d\n",
130 port, err_number));
131 break;
132 }
133 dPrintf(D_M_RTMP, D_L_ERROR, ("Explanation: %s\n", errstr));
134 }
135
136
137 /*
138 * this function just look for a NetNumber in the routing table,
139 * no check is done for the validity of the entry
140 */
141
142 RT_entry *rt_blookup (NetNumber)
143 at_net_al NetNumber;
144 {
145
146 RT_entry *ptree = &RT_table_start;
147 at_net_al LowEnd;
148 /*
149 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Lookup for Net=%d\n",
150 "rt_blookup", NetNumber));
151 */
152 while (ptree) {
153
154 if (NetNumber > ptree->NetStop) {
155 /*
156 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Right from #%d\n",
157 "rt_blookup", ptree->NextIRNet));
158 */
159 ptree = ptree->right;
160 continue;
161 }
162 else {
163 if (ptree->NetStart)
164 LowEnd = ptree->NetStart;
165 else
166 LowEnd = ptree->NetStop;
167
168 if (NetNumber < LowEnd ) {
169 /*
170 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Left from #%d\n",
171 "rt_blookup", ptree->NextIRNet));
172 */
173 ptree = ptree->left;
174 continue;
175 }
176
177 /* we're in the range (either extended or not)
178 * return the entry found.
179 */
180
181 /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : found %04d-%04d Port=%d State=0x%x\n",
182 "rt_blookup", ptree->NetStart, ptree->NetStop, ptree->NetPort,
183 ptree->EntryState));
184 */
185
186 return (ptree);
187 }
188 }
189
190 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n",
191 "rt_blookup", NetNumber));
192 return ((RT_entry *)NULL);
193 }
194
195
196 /* Routing table btree insert routine
197 * Uses a RT_entry parameter as the input, the insert is sorted in
198 * the tree on the NetStop field. Provision is made for non extented
199 * net (ie NetStart = 0).
200 * The function returns the element where the new entry was inserted, or
201 * NULL if the insert didn't work. (In this cas there is a problem with
202 * the tree coherency...
203 *
204 */
205
206
207 RT_entry *rt_binsert (NewEntry)
208 RT_entry *NewEntry;
209 {
210 RT_entry *ptree = &RT_table_start;
211
212 register at_net_al NetStart = NewEntry->NetStart;
213 register at_net_al NetStop = NewEntry->NetStop;
214
215 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("rt_binsert: for Net %d-%d state=x%x NextIR %d:%d\n",
216 NetStart, NetStop, NewEntry->EntryState,NewEntry->NextIRNet, NewEntry->NextIRNode));
217
218 if (ptree == (RT_entry *)NULL) {
219 *ptree = *NewEntry;
220 at_state.flags |= AT_ST_RT_CHANGED;
221 return (NewEntry);
222 }
223
224
225 while (ptree) {
226
227 if (NetStop > ptree->NetStop) { /* walk the right sub-tree */
228 if (ptree->right)
229 ptree = ptree->right;
230 else {
231 ptree->right = NewEntry;
232 at_state.flags |= AT_ST_RT_CHANGED;
233 return (ptree);
234 }
235 }
236 else { /* walk the left sub-tree */
237 if (ptree->left)
238 ptree = ptree->left;
239 else {
240 ptree->left = NewEntry;
241 at_state.flags |= AT_ST_RT_CHANGED;
242 return (ptree);
243 }
244 }
245
246 }
247
248 dPrintf(D_M_RTMP, D_L_WARNING, ("%s : ERROR NOT INSERTED Net %d-%d\n",
249 "rt_binsert", NetStart, NetStop));
250 return ((RT_entry *)NULL);
251 }
252
253 RT_entry *rt_insert(NStop, NStart, NxNet, NxNode, NtDist, NtPort, EntS)
254 at_net_al NStop, NStart, NxNet;
255 at_node NxNode;
256 u_char NtDist, NtPort, EntS;
257 {
258 RT_entry *New;
259 if ((New = RT_table_freelist)) {
260 RT_table_freelist = RT_table_freelist->right;
261 } else
262 return ((RT_entry *)NULL);
263 New->right = NULL;
264 New->NetStop = NStop;
265 New->NetStart = NStart;
266 New->NextIRNet = NxNet;
267 New->NextIRNode = NxNode;
268 New->NetDist = NtDist;
269 New->NetPort = NtPort;
270 New->EntryState = EntS;
271 bzero(New->ZoneBitMap, sizeof(New->ZoneBitMap));
272 at_state.flags |= AT_ST_RT_CHANGED;
273 return(rt_binsert(New));
274 }
275
276 /*
277 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n",
278 "rt_blookup", NetNumber));
279 * Routing table btree deletion routine
280 *
281 */
282
283 RT_entry *rt_bdelete (NetStop, NetStart)
284 at_net_al NetStop, NetStart;
285 {
286
287 RT_entry *rt_found, *pprevious, *pnext, *pnextl, *psub;
288 at_net_al LowEnd;
289
290 rt_found = &RT_table_start;
291
292 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Delete %d-%d\n",
293 "rt_bdelete", NetStart, NetStop));
294
295 while (rt_found) {
296
297 if (NetStop > rt_found->NetStop) {
298 pprevious = rt_found;
299 rt_found = rt_found->right;
300 continue;
301 }
302 else {
303
304 /* non extended nets cases */
305
306 if (rt_found->NetStart)
307 LowEnd = rt_found->NetStart;
308 else
309 LowEnd = rt_found->NetStop;
310
311 if (NetStop < LowEnd) {
312 pprevious = rt_found;
313 rt_found = rt_found->left;
314 continue;
315 }
316
317 /* we're in the range (either extended or not)
318 * return the entry found.
319 */
320
321 break;
322 }
323 }
324
325 dPrintf(D_M_RTMP, D_L_ROUTING, ("%s : Delete %d-%d found to delete %d-%d\n",
326 "rt_bdelete", NetStart, NetStop, rt_found->NetStart,rt_found->NetStop));
327
328 if (rt_found) {
329
330
331
332 /* we found the entry, now reorg the sub-trees
333 * spanning from our node.
334 */
335
336 if ((pnext = rt_found->right)) {
337
338 /* Tree pruning: take the left branch of the current
339 * node and place it at the lowest left branch
340 * of the current right branch
341 */
342
343 psub = pnext;
344
345 /* walk the Right/Left sub tree from current node */
346
347 while ((pnextl = psub->left))
348 psub = pnextl;
349
350 /* plug the old left tree to the new ->Right leftmost node */
351
352 psub->left = rt_found->left;
353
354
355 } else { /* only left sub-tree, simple case */
356
357 pnext = rt_found->left;
358 }
359
360 /* Now, plug the current node sub tree to the good pointer of
361 * our parent node.
362 */
363
364
365 if (pprevious->left == rt_found)
366 pprevious->left = pnext;
367 else
368 pprevious->right = pnext;
369
370 /* clean-up entry and add to the free-list */
371
372 at_state.flags |= AT_ST_RT_CHANGED;
373 return(rt_found);
374 }
375
376 else { /* Trying to delete something that doesn't exist? */
377
378 dPrintf(D_M_RTMP, D_L_WARNING, ("%s : %d NOT Removed\n",
379 "rt_bdelete", NetStop));
380
381 return ((RT_entry *)NULL);
382 }
383
384
385 }
386
387
388 RT_entry *rt_sortedshow(parent)
389 RT_entry *parent;
390 {
391 RT_entry *me;
392
393 me = parent;
394
395 if (parent == NULL) {
396 me = &RT_table_start;
397 while (me)
398 if (me->left) {
399 parent = me;
400 me = me->left;
401 }
402 /* parent = parent->parent; */
403 }
404 return (parent);
405 }
406
407 /*
408 * debug only: display the contents of the routing table
409 */
410
411 void rt_show ()
412 {
413 RT_entry *ptree;
414 int i=0;
415
416 ptree = &RT_table[0];
417
418 while (ptree && i < 600 ) {
419 if (ptree->NetStop) {
420 dPrintf(D_M_RTMP_LOW, D_L_VERBOSE,
421 ("%4d-%4d IR=%d:%d Dist=%d\n",
422 ptree->NetStop, ptree->NetStart, ptree->NextIRNet,
423 ptree->NextIRNode, (short)ptree->NetDist));
424 } else {
425 dPrintf(D_M_RTMP_LOW, D_L_VERBOSE,
426 ("%04d : * FREE ENTRY\n", i));
427 }
428 ptree++;
429 i++;
430 }
431 }
432
433 /*
434 * prepare the indexing of the free entries in the RTMP table
435 */
436
437 rt_table_init()
438 {
439 short i;
440
441 if ((RT_table = (RT_entry *)_MALLOC(sizeof(RT_entry)*RT_maxentry,
442 M_RTABLE, M_WAITOK)) == NULL) {
443 dPrintf(D_M_RTMP, D_L_WARNING,
444 ("rtmptable: Can't allocate RT_table\n"));
445 return (ENOMEM);
446 }
447 if ((ZT_table = (ZT_entry *)_MALLOC(sizeof(ZT_entry)*ZT_maxentry,
448 M_RTABLE, M_WAITOK)) == NULL) {
449 dPrintf(D_M_RTMP, D_L_WARNING,
450 ("rtmptable: Can't allocate ZT_table\n"));
451 return (ENOMEM);
452 }
453 dPrintf(D_M_RTMP, D_L_STARTUP, ("rt_table_init called\n"));
454 bzero(&RT_table[0], sizeof(RT_entry)* RT_maxentry);
455 for (i= 1 ; i < RT_maxentry ; i++) {
456 (&RT_table[i-1])->right = &RT_table[i];
457 }
458 RT_table_freelist = &RT_table[0];
459
460 at_state.flags |= AT_ST_RT_CHANGED;
461 at_state.flags |= AT_ST_ZT_CHANGED;
462 bzero(&RT_table_start, sizeof(RT_entry));
463
464 /* also clean up the ZIP table */
465
466 bzero(&ZT_table[0], sizeof(ZT_entry)* ZT_maxentry);
467 ErrorRTMPoverflow = 0;
468 ErrorZIPoverflow = 0;
469 return(0);
470 }
471
472 /*
473 * zt_add_zone: add a zone name in the zone table.
474 */
475
476 zt_add_zone(name, length)
477 char *name;
478 short length;
479 {
480 at_nvestr_t zname;
481 bcopy(name, &zname.str, length);
482 zname.len = length;
483 return (zt_add_zonename(&zname));
484 }
485
486 /*
487 * zt_add_zonename: add a zone name in the zone table.
488 */
489
490 int zt_add_zonename(zname)
491 at_nvestr_t *zname;
492 {
493 register short res,i;
494
495 if (res = zt_find_zname(zname))
496 return(res);
497
498 for (i = 0; i < ZT_maxentry ; i++) {
499 if (ZT_table[i].ZoneCount == 0 && ZT_table[i].Zone.len == 0) {/* free entry */
500 ZT_table[i].Zone = *zname;
501 dPrintf(D_M_RTMP, D_L_VERBOSE, ("zt_add_zonename: zone #%d %s len=%d\n",
502 i, ZT_table[i].Zone.str, ZT_table[i].Zone.len));
503 at_state.flags |= AT_ST_ZT_CHANGED;
504 return(i+1);
505 }
506 }
507 /* table full... */
508 return (ZT_MAXEDOUT);
509 }
510
511 /* Adjust zone counts for a removed network entry.
512 * If the ZoneCount of a zone reaches zero, delete the zone from the zone table
513 */
514 void zt_remove_zones(zmap)
515 u_char *zmap;
516 {
517
518 register u_short i,j, Index;
519
520 for (i=0; i< ZT_BYTES ; i++) {
521
522 if (zmap[i]) {
523 for (j=0; j < 8 ; j++)
524 if ((zmap[i] << j) & 0x80) {
525 Index = i*8 + j; /* get the index in ZT */
526 /* 1-23-97 this routine caused a crash once, presumably
527 zmap bits beyond ZT_table size got set somehow.
528 prevent that here
529 */
530 if (Index >= ZT_maxentry) {
531 dPrintf(D_M_RTMP, D_L_ERROR,
532 ("zt_remove_zones: index (%d) GT ZT_maxentry (%d) (zmap:%d)\n",
533 Index,ZT_maxentry,i));
534 return;
535 }
536 dPrintf(D_M_RTMP, D_L_VERBOSE,
537 ("zt_remove_zones: zone #%d %s was=%d\n", Index,
538 ZT_table[Index].Zone.str, ZT_table[Index].ZoneCount));
539 if (ZT_table[Index].ZoneCount > 0)
540 ZT_table[Index].ZoneCount--;
541 if (ZT_table[Index].ZoneCount == 0)
542 ZT_table[Index].Zone.len = 0;
543 at_state.flags |= AT_ST_ZT_CHANGED;
544 }
545 }
546 }
547 }
548
549
550
551 /*
552 * zt_compute_hash: compute hash index from the zone name string
553 */
554
555 short zt_compute_hash(zname)
556 at_nvestr_t *zname;
557 {
558 register u_short checksum=0, i;
559 register char c1;
560
561 /* apply the upper name + DDP checksum algorithm */
562
563 for (i= 0 ; i < zname->len; i++) {
564
565 /* upperize the character */
566
567 c1 = zname->str[i];
568 if (c1 >= 'a' && c1 <= 'z')
569 c1 += 'A' - 'a';
570 if (c1 & 0x80)
571 c1 = upshift8(c1);
572
573 /* DDP Checksum */
574
575 checksum += c1;
576 checksum = ((checksum & 0x8000) ?
577 (checksum << 1 | 1) : (checksum << 1));
578 }
579
580 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_comphash: value computed for zone=%s h=%d\n",
581 zname->str, checksum));
582
583 if (checksum)
584 return (checksum);
585 else
586 return (0xffff);
587
588 }
589
590 /*
591 * zt_upper_zname: translate the name string into uppercase
592 */
593
594 void zt_upper_zname(zname)
595 at_nvestr_t *zname;
596 {
597 register short i;
598 register char c1;
599
600 for (i= 0 ; i < zname->len; i++) {
601
602 c1 = zname->str[i];
603 if (c1 >= 'a' && c1 <= 'z')
604 c1 += 'A' - 'a';
605 if (c1 & 0x80)
606 c1 = upshift8(c1);
607
608 zname->str[i] = c1;
609 }
610 }
611
612 /*
613 * zt_get_zmcast: calcularte the zone multicast address for a
614 * given zone name.
615 * Returns the result in "buffer"
616 */
617
618 zt_get_zmcast(ifID, zname, buffer)
619 at_ifaddr_t *ifID; /* we want to know the media type */
620 at_nvestr_t *zname; /* source name for multicast address */
621 char *buffer; /* resulting Zone Multicast address */
622 {
623 u_short h;
624
625 h = zt_compute_hash(zname);
626
627 /*
628 * Find a nice way to decide if it is TokenRing or Ethernet for
629 * the Multicast address computation....
630 */
631
632 if (ifID->aa_ifp->if_type != IFT_ISO88025) { /* token ring */
633
634 /* Ethernet case */
635
636 buffer[0] = 0x09;
637 buffer[1] = 0x00;
638 buffer[2] = 0x07;
639 /* no router, use cable multicast */
640 if (MULTIHOME_MODE && ifID->ifRouterState == NO_ROUTER ) {
641 buffer[3] = buffer[4] = buffer[5] = 0xff;
642 }
643 else {
644 buffer[3] = 0x00;
645 buffer[4] = 0x00;
646 buffer[5] = h % 0xFD;
647 }
648 dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_get_multi: computed for h=%d %x %x\n",
649 h, *(u_int *)&buffer[0], *(u_short *)&buffer[4]));
650
651 return(6); /* returns Multicast address length */
652
653 }
654 else {
655 /* assume it is token ring: note for the magic number computation,
656 * first see Inside Mac Page 3-10, there is 20 multicast addresses
657 * for TLAP, and they are from 0xC000 0000 0008 00 to 0xC000 0200 0000 00
658 */
659 buffer[0] = 0xC0;
660 buffer[1] = 0x00;
661 *(u_int *)&buffer[2] = 1 << ((h % 19) + 11);
662 dPrintf(D_M_RTMP, D_L_WARNING,("zt_get_multi: BROAD not found forr h=%d \n",
663 h));
664 return(6);
665 }
666
667
668
669 }
670
671 /*
672 * zt_ent_zindex: return the first zone index found in the zone map
673 * return the entry number+1 in the Zone Table, or zero if not found
674 */
675
676 int zt_ent_zindex(zmap)
677 u_char *zmap;
678 {
679 u_short i,j;
680
681
682 for (i = 0 ; i < ZT_BYTES ; i++)
683
684 if (zmap[i])
685 for (j = 0 ; j < 8 ; j++)
686 if ((zmap[i] << j) & 0x80)
687 return (8*i + j +1);
688
689 return (0);
690 }
691 /*
692 * zt_ent_zcount: count the number of actives zone for a routing entry
693 */
694
695 zt_ent_zcount(ent)
696 RT_entry *ent;
697 {
698 register u_char *zmap;
699 register u_short i,j;
700 register int zone_count = 0 ;
701
702
703 if (!RT_ALL_ZONES_KNOWN(ent))
704 return (0);
705 zmap = ent->ZoneBitMap;
706
707 for (i = 0 ; i < ZT_BYTES ; i++) {
708
709 if (*zmap)
710
711 for (j = 0 ; j < 8 ; j++)
712 if ((*zmap << j) & 0x80)
713 zone_count++;
714 zmap++;
715 }
716
717 return (zone_count);
718 }
719
720 /*
721 * zt_find_zname: match a zone name in the zone table and return the entry if found
722 */
723 zt_find_zname(zname)
724 at_nvestr_t *zname;
725 {
726 register short i, j, found;
727 register char c1, c2;
728
729
730 if (!zname->len)
731 return(0);
732
733 for (i = 0 ; i < ZT_maxentry ; i++) {
734 if (!ZT_table[i].ZoneCount || zname->len != ZT_table[i].Zone.len)
735 continue;
736
737 found = 1; /* did we get the right one? */
738
739 for (j = 0 ; j < zname->len ; j++) {
740 c1 = zname->str[j];
741 c2 = ZT_table[i].Zone.str[j];
742 if (c1 >= 'a' && c1 <= 'z')
743 c1 += 'A' - 'a';
744 if (c2 >= 'a' && c2 <= 'z')
745 c2 += 'A' - 'a';
746 if (c1 & 0x80)
747 c1 = upshift8(c1);
748 if (c2 & 0x80)
749 c2 = upshift8(c2);
750 if (c1 != c2) {
751 found = 0;
752 break;
753 }
754 }
755
756 if (found)
757 return (i+1);
758 }
759
760 return(0);
761 }
762
763
764 /*
765 * zt_set_zmap: set a bit for the corresponding zone map in an entry bitmap
766 */
767 void zt_set_zmap(znum, zmap)
768 u_short znum;
769 char *zmap;
770 {
771 register u_short num = znum -1;
772
773 if (!(zmap[num >> 3] & 0x80 >> (num % 8))) {
774 zmap[num >> 3] |= 0x80 >> (num % 8);
775 ZT_table[num].ZoneCount++;
776 }
777 }
778
779
780 /*
781 * zt_clr_zmap: clear a bit for the corresponding zone map in an entry bitmap
782 */
783 void zt_clr_zmap(znum, zmap)
784 u_short znum;
785 char *zmap;
786 {
787 register u_short num = znum -1;
788
789 if (zmap[num >> 3] & 0x80 >> (num % 8)) {
790 zmap[num >> 3] ^= 0x80 >> (num % 8);
791 ZT_table[num].ZoneCount--;
792 }
793 }
794
795
796 /*
797 * routing_needed :
798 * This function performs the actual lookup and forward of packets
799 * send to the box for routing.
800 *
801 * The destination network is looked up in our tables, and if we
802 * know the next IR to send the packet to, we forward the packet
803 * on the right port.
804 *
805 * If the destination is unknown, we simply dump the packet.
806 */
807
808 void routing_needed(mp, ifID, bypass)
809 gbuf_t *mp;
810 at_ifaddr_t *ifID;
811 char bypass; /* set by special socket handlers */
812 {
813
814 register at_ddp_t *ddp;
815 register int msgsize;
816 register RT_entry *Entry;
817 register gbuf_t *tmp_m;
818
819 /* first check the interface is up and forwarding */
820
821 if (!ifID) {
822 dPrintf(D_M_RTMP, D_L_WARNING,
823 ("routing_needed: non valid IFID!\n"));
824 gbuf_freel(mp);
825 return;
826 }
827 if ((ifID->ifRoutingState < PORT_ONLINE)) {
828 dPrintf(D_M_RTMP, D_L_WARNING,
829 ("routing_needed: port %d not online yet\n",
830 ifID->ifPort));
831 gbuf_freel(mp);
832 return;
833 }
834
835 ddp = (at_ddp_t *)gbuf_rptr(mp);
836 msgsize = DDPLEN_VALUE(ddp);
837 for (tmp_m = gbuf_next(mp); tmp_m; tmp_m = gbuf_next(tmp_m))
838 msgsize += DDPLEN_VALUE(((at_ddp_t *)gbuf_rptr(tmp_m)));
839
840 if (ddp->hopcount++ > 15) {
841 dPrintf(D_M_RTMP, D_L_WARNING,
842 ("routing_needed: drop packet for %d:%d, hopcount too high\n",
843 NET_VALUE(ddp->dst_net), ddp->dst_node));
844 gbuf_freel(mp);
845 snmpStats.dd_hopCount++;
846 return; /* was return(1); */
847 }
848
849 if ((Entry = rt_blookup(NET_VALUE(ddp->dst_net)))) {
850
851 dPrintf(D_M_RTMP_LOW, D_L_ROUTING,
852 ("routing_needed: FOUND for %d.%d p=%d to %d.%d \n",
853 NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort,
854 Entry->NextIRNet, Entry->NextIRNode));
855
856 /* somehow, come to that point... */
857
858 /* if multihomed - need to set source address to the interface
859 * the packet is being sent from.
860 */
861 if (MULTIHOME_MODE) {
862 NET_ASSIGN(ddp->src_net, ifID_table[Entry->NetPort]->ifThisNode.s_net);
863 ddp->src_node = ifID_table[Entry->NetPort]->ifThisNode.s_node;
864 }
865
866 ifID->ifStatistics.fwdPkts++;
867 ifID->ifStatistics.fwdBytes += msgsize;
868
869 if (Entry->NetDist) /* net not directly connected */
870 ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR,
871 Entry->NextIRNet, Entry->NextIRNode, 0);
872 else {/* we are directly on this net */
873
874 /* we want to avoid duplicating broadcast packet on the same net,
875 * but special sockets handlers are ok to do that (mainly for
876 * for loopback purpose). So, if the "bypass" flag is set, we don't
877 * check for that test... [Problem was "movietalk"].
878 */
879
880 if (bypass || ifID_table[Entry->NetPort] != ifID)
881 ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR,
882 NET_VALUE(ddp->dst_net), ddp->dst_node, 0);
883 else {
884 dPrintf(D_M_RTMP, D_L_ROUTING,
885 ("routing_needed: bad loopback for add %d.%d from port %d (%d.%d)\n",
886 NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort,
887 NET_VALUE(ddp->src_net), ddp->src_node));
888 ifID->ifStatistics.droppedPkts++;
889 ifID->ifStatistics.droppedBytes += msgsize;
890
891 gbuf_freel(mp);
892 return; /* was return (2); */
893 }
894
895
896 }
897 }
898 else {
899 dPrintf(D_M_RTMP, D_L_ROUTING,
900 ("routing_needed: NOT FOUND for add %d.%d from port %d our %d.%d\n",
901 NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort,
902 ifID_home->ifThisNode.s_net,
903 ifID_home->ifThisNode.s_node));
904
905 ifID->ifStatistics.droppedPkts++;
906 ifID->ifStatistics.droppedBytes += msgsize;
907 snmpStats.dd_noRoutes++;
908
909 gbuf_freel(mp);
910 return; /* was return (2); */
911
912 }
913 /* return(0); */
914 } /* routing_needed */
915
916 ZT_entryno *zt_getNextZone(first)
917 int first;
918 /* a call made with first = TRUE returns the first valid entry in
919 the ZT_table, if first != TRUE, then then each call returns the
920 next valid entry in the table. The next call after the last
921 valid entry was read returns NULL
922 */
923 {
924 int i;
925 static int idx=0;
926 static ZT_entryno zte;
927
928 if (!ZT_table)
929 return NULL;
930
931 if (first)
932 idx=0;
933
934 for (i=idx; i<ZT_maxentry; i++) {
935 if (ZT_table[i].ZoneCount)
936 break;
937 }
938 if (i<ZT_maxentry) {
939 idx = i+1;
940 zte.zt = ZT_table[i];
941 zte.entryno = i;
942 return(&zte);
943 }
944 else
945 return(NULL);
946 }
947
948 RT_entry *rt_getNextRoute(first)
949 int first;
950
951 /* a call made with first = TRUE returns the first valid entry in
952 the RT_table, if first != TRUE, then then each call returns the
953 next valid entry in the table. The next call after the last
954 valid entry was read returns NULL
955 */
956
957 {
958 int i;
959 static int idx=0;
960
961 if (!RT_table)
962 return(NULL);
963
964 if (first)
965 idx=0;
966
967 for (i=idx; i<RT_maxentry; i++) {
968 if (RT_table[i].EntryState != RTE_STATE_UNUSED)
969 break;
970 }
971 if (i<RT_maxentry) {
972 idx = i+1;
973 return(&RT_table[i]);
974 }
975 else
976 return(NULL);
977 }
978
979
980 getRtmpTableSize()
981 {
982 register int i;
983 register RT_entry *rt;
984 static int size=0;
985
986 if(!(at_state.flags &AT_ST_RT_CHANGED))
987 return(size);
988
989 for (i=RT_maxentry,rt = &RT_table[RT_maxentry-1]; i; i--,rt--)
990 if (rt->EntryState != RTE_STATE_UNUSED) {
991 size = i;
992 return(i);
993 }
994 return(0);
995 }
996
997 getZipTableSize()
998 {
999 register int i;
1000 register ZT_entry *zt;
1001 static int size=0;
1002
1003 if (!(at_state.flags & AT_ST_ZT_CHANGED))
1004 return(size);
1005
1006 for (i=ZT_maxentry,zt = &ZT_table[ZT_maxentry-1]; i; i--,zt--)
1007 if (zt->ZoneCount) {
1008 size = i;
1009 return(i);
1010 }
1011 return(0);
1012 }
1013
1014 getRtmpTable(d,s,c)
1015 RT_entry *d; /* destination */
1016 int s; /* starting entry */
1017 int c; /* # entries to copy */
1018 {
1019 register int i,n=0;
1020 register RT_entry *rt;
1021
1022 for(i=s,rt=&RT_table[s]; i<RT_maxentry && n<c; rt++,i++)
1023 if (rt->EntryState != RTE_STATE_UNUSED) {
1024 *d++ = *rt;
1025 n++;
1026 }
1027 }
1028
1029 getZipTable(d,s,c)
1030 ZT_entry *d; /* destination */
1031 int s; /* starting entry */
1032 int c; /* # entries to copy */
1033 {
1034
1035 bcopy(&ZT_table[s], d, c*sizeof(ZT_entry));
1036 }
1037
1038 at_nvestr_t *getRTRLocalZone(ifz)
1039 zone_usage_t *ifz;
1040 {
1041 char *zmap;
1042 RT_entry *route;
1043 int i, j, index;
1044 int zcnt=0; /* zone we're pointing to in the list */
1045 char zonesChecked[ZT_BYTES];
1046 at_ifaddr_t *ifID;
1047
1048 if (ifz->zone_index < 0) {
1049 return((at_nvestr_t*)NULL);
1050 }
1051 bzero(zonesChecked,sizeof(zonesChecked));
1052 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1053 if (!(route = rt_blookup(ifID->ifThisNode.s_net))) {
1054 return((at_nvestr_t*)NULL);
1055 }
1056 zmap=route->ZoneBitMap;
1057 dPrintf(D_M_RTMP_LOW, D_L_USR1,
1058 ("getRTRLocal: i/f %s, net:%d\n",ifID->ifName,
1059 ifID->ifThisNode.s_net));
1060 for (i = 0 ; i < ZT_BYTES; i++) {
1061 if (zmap[i]) {
1062 for (j = 0; j < 8 ; j++)
1063 if ( (zmap[i] & (0x80 >> j)) &&
1064 !(zonesChecked[i] & (0x80 >> j))
1065 ) {
1066 zonesChecked[i] |= (0x80 >> j);
1067 if (ifz->zone_index == zcnt) {
1068 index = i * 8 + j;
1069 getIfUsage(index, &ifz->zone_iflist);
1070 ifz->zone_name = ZT_table[index].Zone;
1071 dPrintf(D_M_RTMP_LOW, D_L_USR1,
1072 ("getRTRLocal:zmap:%8x zcnt:%d\n",
1073 *(int*)zmap, zcnt));
1074 ifz->zone_index = index+1;
1075 return(&ZT_table[index].Zone);
1076 }
1077 zcnt++;
1078 }
1079 }
1080 }
1081 }
1082 dPrintf(D_M_RTMP_LOW, D_L_USR1,
1083 ("getRTRLocal: returning NULL last ent:%d net:%d zmap:%08x\n",
1084 (ifID ? ifID->ifPort : 0),
1085 (ifID ? ifID->ifThisNode.s_net : 0),*(int*)zmap));
1086 ifz->zone_name.len = 0;
1087 return((at_nvestr_t*)NULL);
1088 } /* getRTRLocalZone */
1089
1090 void getIfUsage(zone, ifs_in_zone)
1091 int zone;
1092 at_ifnames_t *ifs_in_zone;
1093
1094 /* sets the interface name in each element of the array for each I/F in the
1095 requested zone. The array has a 1:1 correspondence with the
1096 ifID_table. Zone is assumed to be valid and local, so if we're in
1097 single port mode, we'll set the home port and thats it.
1098 */
1099 {
1100 u_int zmi; /* zone map index for zone */
1101 u_char zmb; /* zone map bit mask for zone */
1102 RT_entry *route;
1103 int cnt=0;
1104 at_ifaddr_t *ifID;
1105
1106 if (!MULTIPORT_MODE) {
1107 strncpy(ifs_in_zone->at_if[cnt], ifID_home->ifName,
1108 IFNAMESIZ);
1109 return;
1110 }
1111 bzero(ifs_in_zone, sizeof(at_ifnames_t));
1112 zmi = zone>>3;
1113 zmb = 0x80>>(zone % 8);
1114 dPrintf(D_M_NBP_LOW, D_L_USR3, ("get_ifs znum:%d zmi%d zmb:%x\n",
1115 zone, zmi, zmb));
1116 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1117 if (!(route = rt_blookup(ifID->ifThisNode.s_net)))
1118 return;
1119 if (route->ZoneBitMap[zmi] & zmb) {
1120 dPrintf(D_M_NBP_LOW, D_L_USR3, ("zone in port %d \n",
1121 route->NetPort));
1122 strncpy(ifs_in_zone->at_if[cnt],
1123 ifID_table[route->NetPort]->ifName, IFNAMESIZ);
1124 cnt++;
1125 }
1126 }
1127 return;
1128 } /* getIfUsage */