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