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