1/*
2 * Copyright (c) 1994, 1996-2000 Apple Computer, 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 * Router RTMP protocol functions:
30 *
31 * This file contains Routing specifics to handle RTMP packets and
32 * the maintenance of the routing table through....
33 *
34 * The entry point for the rtmp input in ddp is valid only when we're
35 * running in router mode.
36 *
37 *
38 * 0.01 03/22/94	Laurent Dumont		Creation
39 *    Modified for MP, 1996 by Tuyen Nguyen
40 *    Added AURP support, April 8, 1996 by Tuyen Nguyen
41 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
42 *
43 *-------------------------------------------------------------------------
44 */
45
46#include <sys/errno.h>
47#include <sys/types.h>
48#include <sys/param.h>
49#include <machine/spl.h>
50#include <sys/systm.h>
51#include <sys/kernel.h>
52#include <sys/proc.h>
53#include <sys/filedesc.h>
54#include <sys/fcntl.h>
55#include <sys/mbuf.h>
56#include <sys/ioctl.h>
57#include <sys/malloc.h>
58#include <kern/locks.h>
59#include <sys/socket.h>
60#include <sys/socketvar.h>
61
62#include <net/if.h>
63
64#include <netat/sysglue.h>
65#include <netat/appletalk.h>
66#include <netat/at_pcb.h>
67#include <netat/at_var.h>
68#include <netat/ddp.h>
69#include <netat/rtmp.h>
70#include <netat/zip.h>
71#include <netat/routing_tables.h>
72#include <netat/aurp.h>
73#include <netat/debug.h>
74
75#include <sys/kern_event.h>
76
77extern void (*ddp_AURPsendx)(void);
78extern at_ifaddr_t *aurp_ifID;
79extern at_ifaddr_t *ifID_table[];
80extern at_ifaddr_t *ifID_home;
81
82
83int rtmp_router_start(at_kern_err_t *);
84void rtmp_router_start_tmo(void *);
85
86
87
88static at_kern_err_t ke;
89			/* Used to record error discovered in rtmp_update() */
90
91void rtmp_timeout(void *arg);
92void rtmp_send_port(at_ifaddr_t *);
93void rtmp_send_port_locked(void *);
94void rtmp_dropper(void *);
95static void rtmp_update(at_ifaddr_t *, at_rtmp *, short);
96static void rtmp_request(at_ifaddr_t *, at_ddp_t *);
97int elap_online3(at_ifaddr_t	*);
98
99extern short ErrorRTMPoverflow, ErrorZIPoverflow;
100extern lck_mtx_t * atalk_mutex;
101
102extern int pktsIn, pktsOut, pktsDropped, pktsHome;
103
104
105/*
106 * rtmp_router_input: function called by DDP (in router mode) to handle
107 *                    all incoming RTMP packets. Listen to the RTMP socket
108 *                    for all the connected ports.
109 *					  Switch to the relevant rtmp functions.
110 */
111
112void rtmp_router_input(mp, ifID)
113     register gbuf_t  *mp;
114     register at_ifaddr_t        *ifID;
115{
116        register at_ddp_t *ddp = (at_ddp_t *)gbuf_rptr(mp);
117                          /* NOTE: there is an assumption here that the
118			   * DATA follows the header. */
119
120	register at_net_al OurNet;
121	register at_node OurNode;
122	register at_net_al DstNet;
123	register at_node DstNode;
124	short tuples;
125	RT_entry *Entry;
126
127    	if (!ifID || (ifID->ifRoutingState < PORT_ACTIVATING)) {
128                gbuf_freem(mp);
129                return;
130        }
131
132
133	OurNet = ifID->ifThisNode.s_net;
134	OurNode = ifID->ifThisNode.s_node;
135
136
137        if (gbuf_type(mp) != MSG_DATA) {
138
139                /* If this is a M_ERROR message, DDP is shutting down,
140                 * nothing to do here...If it's something else, we don't
141                 * understand what it is
142                 */
143		dPrintf(D_M_RTMP, D_L_WARNING,
144			("rtmp_router_input: Not an M_DATA type\n"));
145                gbuf_freem(mp);
146                return;
147        }
148
149	DstNet = NET_VALUE(ddp->dst_net);
150	DstNode = ddp->dst_node;
151
152	/* check the kind of RTMP packet we received */
153
154	switch (ddp->type) {
155
156	case DDP_RTMP:
157
158		tuples = gbuf_len(mp) - DDP_X_HDR_SIZE - RTMP_IDLENGTH;
159		/*
160		 * we need to make sure that the size of 'tuples' is
161		 * not less than or equal to 0 due to a bad packet
162		 */
163		if (tuples <= 0) {
164			gbuf_freem(mp);
165			break;
166		}
167
168		if (tuples % 3)	{/* not a valid RTMP data packet */
169			gbuf_freem(mp);
170			dPrintf(D_M_RTMP, D_L_WARNING,
171				("rtmp_input: bad number of tuple in RTMP packet\n"));
172			return;
173		}
174
175		tuples = tuples / 3;
176
177		rtmp_update(ifID, (at_rtmp *)ddp->data, tuples);
178		gbuf_freem(mp);
179
180		break;
181
182	case DDP_RTMP_REQ:
183
184		/* we should treat requests a bit differently.
185		 * - if the request if not for the port, route it and also respond
186		 *   for this port if not locally connected.
187		 * - if the request for this port, then just respond to it.
188		 */
189
190		if (!ROUTING_MODE) {
191			gbuf_freem(mp);
192			return;
193		}
194		if (DstNode == 255) {
195			if (((DstNet >= CableStart) && (DstNet <= CableStop)) ||
196			    DstNet == 0) {
197				rtmp_request(ifID, ddp);
198				gbuf_freem(mp);
199				return;
200			}
201			else {
202				/* check if directly connected port */
203				if ((Entry = rt_blookup(DstNet)) &&
204				    (Entry->NetDist == 0)) {
205				  dPrintf(D_M_RTMP, D_L_WARNING,
206					  ("rtmp_router_input: request for %d.%d, port %d\n",
207					   DstNet, DstNode, Entry->NetPort));
208				  rtmp_request(ifID_table[Entry->NetPort], ddp);
209				  gbuf_freem(mp);
210				  return;
211				}
212				else {
213				  dPrintf(D_M_RTMP, D_L_WARNING,
214					  ("rtmp_router_input: RTMP packet received for %d.%d, also forward\n",
215					   NET_VALUE(ddp->dst_net),ddp->dst_node));
216				  routing_needed(mp, ifID, TRUE);
217				  return;
218				}
219			}
220		}
221		else {
222
223			if ((DstNode == OurNode) && (DstNet == OurNet)) {
224				rtmp_request(ifID, ddp);
225				gbuf_freem(mp);
226				return;
227			}
228			else  {
229			  dPrintf(D_M_RTMP, D_L_WARNING,
230				  ("rtmp_router_input: RTMP packet received for %d.%d, forward\n",
231				   NET_VALUE(ddp->dst_net), ddp->dst_node));
232			  routing_needed(mp, ifID, TRUE);
233			}
234		}
235
236		break;
237
238	default:
239
240		dPrintf(D_M_RTMP, D_L_WARNING,
241			("rtmp_input: RTMP packet type=%d, route it\n", ddp->type));
242		routing_needed(mp, ifID, TRUE);
243		break;
244
245	}
246} /* rtmp_router_input */
247
248/*
249 * rtmp_update:
250 *
251 */
252
253static void rtmp_update(ifID, rtmp, tuple_nb)
254     register at_ifaddr_t 	*ifID;
255     register at_rtmp 	*rtmp;
256     register short	tuple_nb;
257{
258	register int PortFlags = ifID->ifFlags;
259	register at_rtmp_tuple *FirstTuple =  (at_rtmp_tuple *)&rtmp->at_rtmp_id[1];
260	register at_rtmp_tuple *SecondTuple = (at_rtmp_tuple *)&rtmp->at_rtmp_id[4];
261	RT_entry NewRoute, *CurrentRoute;
262	register u_char SenderNodeID = rtmp->at_rtmp_id[0];
263	char *TuplePtr;
264	short state;
265
266	bzero(&NewRoute, sizeof(RT_entry));
267
268	/* Make sure this an AppleTalk node sending us the RTMP packet */
269
270	if (rtmp->at_rtmp_id_length  != 8) {
271		dPrintf(D_M_RTMP, D_L_WARNING,
272			("rtmp_update : RTMP ID not as expected Net=%d L=x%x\n",
273			 NET_VALUE(rtmp->at_rtmp_this_net), rtmp->at_rtmp_id_length));
274		return;
275	}
276
277	/*
278	 * If the port is activating, only take the Network range from the
279         * the RTMP packet received.
280	 * Check if there is a conflict with our seed infos.
281         */
282
283	if (ifID->ifRoutingState == PORT_ACTIVATING) {
284		if (PortFlags & RTR_XNET_PORT) {
285			if ((PortFlags & RTR_SEED_PORT) &&
286			    ((CableStart != TUPLENET(FirstTuple)) ||
287			     (CableStop != TUPLENET(SecondTuple)))) {
288				ifID->ifRoutingState = PORT_ERR_SEED;
289				ke.error 	= KE_CONF_SEED_RNG;
290				ke.port1 	= ifID->ifPort;
291				strlcpy(ke.name1, ifID->ifName, sizeof(ke.name1));
292				ke.net 		=  NET_VALUE(rtmp->at_rtmp_this_net);
293				ke.node     = SenderNodeID;
294				ke.netr1b 	= TUPLENET(FirstTuple);
295				ke.netr1e 	= TUPLENET(SecondTuple);
296				ke.netr2b 	= CableStart;
297				ke.netr2e	= CableStop;
298				RouterError(ifID->ifPort, ERTR_SEED_CONFLICT);
299				return;
300			}
301			CableStart = TUPLENET(FirstTuple);
302			CableStop  = TUPLENET(SecondTuple);
303/*
304			dPrintf(D_M_RTMP, D_L_INFO,
305				("rtmp_update: Port #%d activating, set Cable %d-%d\n",
306				ifID->ifPort, CableStart, CableStop));
307*/
308		}
309		else { /* non extended cable */
310			if ((PortFlags & RTR_SEED_PORT) &&
311			    (ifID->ifThisCableEnd != NET_VALUE(rtmp->at_rtmp_this_net))) {
312				ke.error 	= KE_CONF_SEED1;
313				ke.port1 	= ifID->ifPort;
314				strlcpy(ke.name1, ifID->ifName,sizeof(ke.name1));
315				ke.net 		=  NET_VALUE(rtmp->at_rtmp_this_net);
316				ke.node     = SenderNodeID;
317				ke.netr1e 	= ifID->ifThisCableEnd;
318				ifID->ifRoutingState = PORT_ERR_SEED;
319				RouterError(ifID->ifPort, ERTR_SEED_CONFLICT);
320				return;
321			}
322			CableStop =  NET_VALUE(rtmp->at_rtmp_this_net);
323			CableStart = 0;
324			dPrintf(D_M_RTMP, D_L_INFO,
325				("rtmp_update: Port #%d NONX activating, set Cable %d-%d\n",
326				 ifID->ifPort, CableStart, CableStop));
327		}
328	}
329
330	/*
331	 * Perform a few sanity checks on the received RTMP data packet
332         */
333
334	if ((PortFlags & RTR_XNET_PORT) && (tuple_nb >= 2)) {
335
336		/* The first tuple must be extended */
337
338		if (! TUPLERANGE(FirstTuple)) {
339			dPrintf(D_M_RTMP, D_L_WARNING,
340				("rtmp_update: bad range value in 1st tuple =%d\n",
341				 TUPLERANGE(FirstTuple)));
342			return;
343		}
344
345		if (PortFlags & RTR_SEED_PORT)
346			if ((TUPLENET(FirstTuple) != CableStart) ||
347			    (TUPLENET(SecondTuple) != CableStop)) {
348				dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_update: conflict on Seed Port\n"));
349				ifID->ifRoutingState = PORT_ERR_CABLER;
350				ke.error 	= KE_CONF_SEED_NODE;
351				ke.port1 	= ifID->ifPort;
352				strlcpy(ke.name1, ifID->ifName,sizeof(ke.name1));
353				ke.net 		=  NET_VALUE(rtmp->at_rtmp_this_net);
354				ke.node     = SenderNodeID;
355				ke.netr1b 	= TUPLENET(FirstTuple);
356				ke.netr1e 	= TUPLENET(SecondTuple);
357				ke.netr2b 	= CableStart;
358				ke.netr2e	= CableStop;
359				RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT);
360				return;
361			}
362
363		/* check that the tuple matches the range */
364
365		if ((TUPLENET(SecondTuple) < TUPLENET(FirstTuple)) ||
366		    (TUPLENET(FirstTuple) == 0) ||
367		    (TUPLENET(FirstTuple) >= DDP_STARTUP_LOW) ||
368		    (TUPLENET(SecondTuple) == 0) ||
369		    (TUPLENET(SecondTuple) >= DDP_STARTUP_LOW)) {
370
371			/*
372			 * IS THIS NON-FATAL?????
373			 */
374			dPrintf(D_M_RTMP, D_L_WARNING,
375				("rtmp_update: STARTUP RANGE!!! 1st %d-%d\n",
376				 TUPLENET(FirstTuple), TUPLENET(SecondTuple)));
377			ifID->ifRoutingState = PORT_ERR_STARTUP;
378			ke.error 	= KE_SEED_STARTUP;
379			ke.port1 	= ifID->ifPort;
380			strlcpy(ke.name1, ifID->ifName,sizeof(ke.name1));
381			ke.net 		=  NET_VALUE(rtmp->at_rtmp_this_net);
382			ke.node     = SenderNodeID;
383			RouterError(ifID->ifPort, ERTR_CABLE_STARTUP);
384			return;
385		}
386
387		if (TUPLEDIST(FirstTuple) != 0) {
388			dPrintf(D_M_RTMP, D_L_WARNING,
389				("rtmp_update: Invalid distance in 1st tuple\n"));
390			return;
391		}
392
393		if (rtmp->at_rtmp_id[6] != RTMP_VERSION_NUMBER) {
394			dPrintf(D_M_RTMP, D_L_WARNING,
395				("rtmp_update: Invalid RTMP version = x%x\n",
396				 rtmp->at_rtmp_id[6]));
397			return;
398		}
399
400	}
401	else {	/* non extended interface or problem in tuple*/
402
403		if (PortFlags & RTR_XNET_PORT) {
404			dPrintf(D_M_RTMP, D_L_WARNING,
405				("rtmp_update: invalid number of tuple for X-net\n"));
406			return;
407		}
408
409		if (TUPLENET(FirstTuple) == 0) { /* non extended RTMP data */
410
411			if (rtmp->at_rtmp_id[3] > RTMP_VERSION_NUMBER) {
412				dPrintf(D_M_RTMP, D_L_WARNING,
413					("rtmp_update: Invalid non extended RTMP version\n"));
414				return;
415			}
416
417		}
418		else {
419			dPrintf(D_M_RTMP, D_L_WARNING,
420				("rtmp_update: version 1.0 non Xtended net not supported\n"));
421			ifID->ifRoutingState = PORT_ERR_BADRTMP;
422			ke.error 	= KE_BAD_VER;
423			ke.rtmp_id = rtmp->at_rtmp_id[6];
424			ke.net 		=  NET_VALUE(rtmp->at_rtmp_this_net);
425			ke.node     = SenderNodeID;
426			RouterError(ifID->ifPort, ERTR_RTMP_BAD_VERSION);
427			return;
428		}
429	}
430
431	NewRoute.NextIRNet  = NET_VALUE(rtmp->at_rtmp_this_net);
432	NewRoute.NextIRNode = SenderNodeID;
433	NewRoute.NetPort	= ifID->ifPort;
434
435	/*
436	 * Process the case where a non-seed port needs to acquire the right
437	 * information.
438         */
439
440	if (!(PortFlags & RTR_SEED_PORT) && (ifID->ifRoutingState == PORT_ACTIVATING)) {
441		dPrintf(D_M_RTMP_LOW, D_L_INFO,
442			("rtmp_update: Port# %d, set non seed cable %d-%d\n",
443			 ifID->ifPort, TUPLENET(FirstTuple), TUPLENET(SecondTuple)));
444
445		if (PortFlags & RTR_XNET_PORT) {
446			NewRoute.NetStart = TUPLENET(FirstTuple);
447			NewRoute.NetStop = TUPLENET(SecondTuple);
448			ifID->ifThisCableStart = TUPLENET(FirstTuple);
449			ifID->ifThisCableEnd  = TUPLENET(SecondTuple);
450
451		}
452		else {
453
454			NewRoute.NetStart = 0;
455			NewRoute.NetStop  = NET_VALUE(rtmp->at_rtmp_this_net);
456			ifID->ifThisCableStart = NET_VALUE(rtmp->at_rtmp_this_net);
457			ifID->ifThisCableEnd  = NET_VALUE(rtmp->at_rtmp_this_net);
458		}
459		/*
460		 * Now, check if we already know this route, or we need to add it
461		 * (or modify it in the table accordingly)
462		 */
463
464		if ((CurrentRoute = rt_blookup(NewRoute.NetStop)) &&
465		    (CurrentRoute->NetStop  == NewRoute.NetStop) &&
466		    (CurrentRoute->NetStart == NewRoute.NetStart)) {
467/*LD 7/31/95 tempo########*/
468			if (NewRoute.NetPort != CurrentRoute->NetPort) {
469				dPrintf(D_M_RTMP, D_L_WARNING,
470					("rtmp_update: port# %d, not the port we waited for %d\n",
471					 ifID->ifPort, CurrentRoute->NetPort));
472				/* propose to age the entry we know... */
473
474				state = CurrentRoute->EntryState & 0x0F;
475				/* if entry has been updated recently, just clear the UPDATED
476				   bit. if bit not set, then we can age the entry */
477				if (state) {
478					if (CurrentRoute->EntryState & RTE_STATE_UPDATED) {
479						CurrentRoute->EntryState &= ~RTE_STATE_UPDATED;
480					}
481					else {
482						state  = state >> 1 ;	/* decrement state */
483					}
484				}
485				CurrentRoute->EntryState = (CurrentRoute->EntryState & 0xF0) | state;
486			}
487		}
488
489		else { /* add the new route */
490
491			dPrintf(D_M_RTMP, D_L_INFO,
492				("rtmp_update: P# %d, 1st tuple route not known, add %d-%d\n",
493				 ifID->ifPort, NewRoute.NetStart, NewRoute.NetStop));
494
495			NewRoute.EntryState = RTE_STATE_GOOD|RTE_STATE_UPDATED;
496			NewRoute.NetDist	= 0;
497
498			if (rt_insert(NewRoute.NetStop, NewRoute.NetStart, 0,
499				      0, NewRoute.NetDist, NewRoute.NetPort,
500				      NewRoute.EntryState) == (RT_entry *)NULL)
501
502				ErrorRTMPoverflow = 1;
503		}
504
505	}
506
507	if (ifID->ifRoutingState == PORT_ACTIVATING) {
508		dPrintf(D_M_RTMP, D_L_INFO,
509	  		("rtmp_update: port activating, ignoring remaining tuples\n"));
510		return;
511	}
512
513	/*
514	 * Process all the tuples against our routing table
515	 */
516
517	TuplePtr = (char *)FirstTuple;
518
519	while (tuple_nb-- > 0) {
520
521		if (TUPLEDIST(TuplePtr) == NOTIFY_N_DIST) {
522			dPrintf(D_M_RTMP, D_L_INFO,
523				("rtmp_update: Port# %d, Tuple with Notify Neighbour\n",
524				 ifID->ifPort));
525			NewRoute.NetDist = NOTIFY_N_DIST;
526			NewRoute.EntryState = RTE_STATE_BAD;
527		}
528		else {
529			NewRoute.NetDist = TUPLEDIST(TuplePtr) + 1;
530			NewRoute.EntryState = RTE_STATE_GOOD;
531			NewRoute.EntryState = RTE_STATE_GOOD|RTE_STATE_UPDATED;
532		}
533
534
535		if (TUPLERANGE(TuplePtr)) {	/* Extended Tuple */
536
537
538			NewRoute.NetStart = TUPLENET(TuplePtr);
539			TuplePtr += 3;
540			NewRoute.NetStop  = TUPLENET((TuplePtr));
541			TuplePtr += 3;
542			tuple_nb--;
543
544			if ((NewRoute.NetDist  == 0) ||
545			    (NewRoute.NetStart == 0) ||
546			    (NewRoute.NetStop  == 0) ||
547			    (NewRoute.NetStop  < NewRoute.NetStart) ||
548			    (NewRoute.NetStart >= DDP_STARTUP_LOW) ||
549			    (NewRoute.NetStop  >= DDP_STARTUP_LOW)) {
550
551			  dPrintf(D_M_RTMP, D_L_WARNING,
552				  ("rtmp_update: P# %d, non valid xtuple received [%d-%d]\n",
553				   ifID->ifPort, NewRoute.NetStart, NewRoute.NetStop));
554
555						continue;
556			}
557
558		}
559		else {		/* Non Extended Tuple */
560
561			NewRoute.NetStart = 0;
562			NewRoute.NetStop  = TUPLENET(TuplePtr);
563
564			TuplePtr += 3;
565
566			if ((NewRoute.NetDist  == 0) ||
567			    (NewRoute.NetStop  == 0) ||
568			    (NewRoute.NetStop  >= DDP_STARTUP_LOW)) {
569
570			  dPrintf(D_M_RTMP, D_L_WARNING,
571				  ("rtmp_update: P# %d, non valid tuple received [%d]\n",
572				   ifID->ifPort, NewRoute.NetStop));
573
574			  continue;
575			}
576		}
577
578		if ((CurrentRoute = rt_blookup(NewRoute.NetStop))) {
579			/* found something... */
580
581			if (NewRoute.NetDist < 16 ||
582			    NewRoute.NetDist == NOTIFY_N_DIST ) {
583
584				/*
585				 * Check if the definition of the route changed
586				 */
587
588				if (NewRoute.NetStop != CurrentRoute->NetStop ||
589				    NewRoute.NetStart != CurrentRoute->NetStart) {
590
591				  if (NewRoute.NetStop == CurrentRoute->NetStop &&
592				      NewRoute.NetStop == CurrentRoute->NetStart &&
593				      NewRoute.NetStart == 0)
594
595				  	NewRoute.NetStart = NewRoute.NetStop;
596
597				  else if (NewRoute.NetStop == CurrentRoute->NetStop &&
598					   NewRoute.NetStart == NewRoute.NetStop &&
599					   CurrentRoute->NetStart == 0) {
600						dPrintf(D_M_RTMP, D_L_WARNING,
601							("rtmp_update: Range %d-%d has changed to %d-%d Dist=%d\n",
602							 CurrentRoute->NetStart, CurrentRoute->NetStop,
603							 NewRoute.NetStart, NewRoute.NetStop, NewRoute.NetDist));
604						NewRoute.NetStart = 0;
605				  }
606
607				  else {
608					dPrintf(D_M_RTMP, D_L_WARNING,
609						("rtmp_update: Net Conflict Cur=%d, New=%d\n",
610						 CurrentRoute->NetStop, NewRoute.NetStop));
611					CurrentRoute->EntryState =
612					  (CurrentRoute->EntryState & 0xF0) | RTE_STATE_BAD;
613					continue;
614
615				  }
616				}
617
618				/*
619				 * If we don't know the associated zones
620				 */
621
622				if (!RT_ALL_ZONES_KNOWN(CurrentRoute)) {
623
624					dPrintf(D_M_RTMP_LOW, D_L_INFO,
625						("rtmp_update: Zone unknown for %d-%d state=0x%x\n",
626						 CurrentRoute->NetStart, CurrentRoute->NetStop,
627						 CurrentRoute->EntryState));
628
629					/* set the flag in the ifID structure telling
630					 * that a scheduling of Zip Query is needed.
631					 */
632
633					ifID->ifZipNeedQueries = 1;
634					continue;
635				}
636
637				if (((CurrentRoute->EntryState & 0x0F) <= RTE_STATE_SUSPECT) &&
638				    NewRoute.NetDist != NOTIFY_N_DIST) {
639
640					dPrintf(D_M_RTMP, D_L_INFO,
641						("rtmp_update: update suspect entry %d-%d State=%d\n",
642						 NewRoute.NetStart, NewRoute.NetStop,
643						 (CurrentRoute->EntryState & 0x0F)));
644
645					if (NewRoute.NetDist <= CurrentRoute->NetDist) {
646					  CurrentRoute->NetDist 	 = NewRoute.NetDist;
647					  CurrentRoute->NetPort 	 = NewRoute.NetPort;
648					  CurrentRoute->NextIRNode = NewRoute.NextIRNode;
649					  CurrentRoute->NextIRNet  = NewRoute.NextIRNet;
650					  CurrentRoute->EntryState =
651					    (CurrentRoute->EntryState & 0xF0) |
652					    (RTE_STATE_GOOD|RTE_STATE_UPDATED);
653					}
654					continue;
655				}
656				else {
657
658					if (NewRoute.NetDist == NOTIFY_N_DIST) {
659
660						CurrentRoute->EntryState =
661						  (CurrentRoute->EntryState & 0xF0) | RTE_STATE_SUSPECT;
662						CurrentRoute->NetDist = NOTIFY_N_DIST;
663						continue;
664					}
665				}
666
667			}
668
669
670			if ((NewRoute.NetDist <= CurrentRoute->NetDist) && (NewRoute.NetDist <16)) {
671
672				 /* Found a shorter or more recent Route,
673				  * Replace with the New entryi
674				  */
675
676				CurrentRoute->NetDist    = NewRoute.NetDist;
677				CurrentRoute->NetPort    = NewRoute.NetPort;
678				CurrentRoute->NextIRNode = NewRoute.NextIRNode;
679				CurrentRoute->NextIRNet  = NewRoute.NextIRNet;
680				CurrentRoute->EntryState |= RTE_STATE_UPDATED;
681
682				/* Can we consider now that the entry is updated? */
683				dPrintf(D_M_RTMP_LOW, D_L_INFO,
684					("rtmp_update: Shorter route found %d-%d, update\n",
685					 NewRoute.NetStart, NewRoute.NetStop));
686
687#ifdef AURP_SUPPORT
688			if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
689				ddp_AURPsendx(AURPCODE_RTUPDATE,
690					      (void *)&NewRoute, AURPEV_NetDistChange);
691#endif
692			}
693		}
694		else { /* no entry found */
695
696			if (NewRoute.NetDist < 16 && NewRoute.NetDist != NOTIFY_N_DIST &&
697			    NewRoute.NextIRNet >= ifID->ifThisCableStart &&
698			    NewRoute.NextIRNet <= ifID->ifThisCableEnd) {
699
700				NewRoute.EntryState = (RTE_STATE_GOOD|RTE_STATE_UPDATED);
701
702				dPrintf(D_M_RTMP_LOW, D_L_INFO,
703					("rtmp_update: NewRoute %d-%d Tuple #%d\n",
704					 NewRoute.NetStart, NewRoute.NetStop, tuple_nb));
705
706				ifID->ifZipNeedQueries = 1;
707
708				if (rt_insert(NewRoute.NetStop, NewRoute.NetStart, NewRoute.NextIRNet,
709					      NewRoute.NextIRNode, NewRoute.NetDist, NewRoute.NetPort,
710					      NewRoute.EntryState) == (RT_entry *)NULL)
711					ErrorRTMPoverflow = 1;
712#ifdef AURP_SUPPORT
713				else if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
714					ddp_AURPsendx(AURPCODE_RTUPDATE,
715						      (void *)&NewRoute, AURPEV_NetAdded);
716#endif
717			}
718		}
719
720	} /* end of main while */
721	ifID->ifRouterState = ROUTER_UPDATED;
722	if (ifID->ifZipNeedQueries)
723		zip_send_queries(ifID, 0, 0xFF);
724
725/*
726	timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ);
727*/
728} /* rtmp_update */
729
730/* The RTMP validity timer expired, we need to update the
731 * state of each routing entry in the table
732 * because there is only one validity timer and it is always running,
733 * we can't just age all the entries automatically, as we might be
734 * aging entries that were just updated. So, when an entry is updated,
735 * the RTE_STATE_UPDATED bit is set and when the aging routine is called
736 * it just resets this bit if it is set, only if it is not set will the
737 * route actually be aged.
738 * Note there are 4 states for an entry, the state is decremented until
739 * it reaches the bad state. At this point, the entry is removed
740 *
741 *      RTE_STATE_GOOD   :  The entry was valid (will be SUSPECT)
742 *      RTE_STATE_SUSPECT:  The entry was suspect (can still be used for routing)
743 *      RTE_STATE_BAD    : 	The entry was bad and is now deleted
744 *      RTE_STATE_UNUSED :  Unused or removed entry in the table
745 */
746
747void rtmp_timeout(void *arg)
748{
749		at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
750		register u_char state;
751		short i;
752		RT_entry *en = &RT_table[0];
753
754		atalk_lock();
755
756		if (ifID->ifRoutingState < PORT_ONLINE) {
757			atalk_unlock();
758			return;
759                }
760
761		/* for multihoming mode, we use ifRouterState to tell if there
762           is a router out there, so we know when to use cable multicast */
763		if (ifID->ifRouterState > NO_ROUTER)
764			ifID->ifRouterState--;
765
766		for (i = 0 ; i < RT_maxentry; i++,en++) {
767
768			/* we want to age "learned" nets, not directly connected ones */
769			state  = en->EntryState & 0x0F;
770
771
772			if (state > RTE_STATE_UNUSED &&
773			   !(en->EntryState & RTE_STATE_PERMANENT) && en->NetStop &&
774			   en->NetDist && en->NetPort == ifID->ifPort) {
775
776					/* if entry has been updated recently, just clear the UPDATED
777					   bit. if bit not set, then we can age the entry */
778				if (en->EntryState & RTE_STATE_UPDATED) {
779					en->EntryState &= ~RTE_STATE_UPDATED;
780					continue;
781				}
782				else
783					state  = state >> 1 ;	/* decrement state */
784
785				if (state == RTE_STATE_UNUSED)	{/* was BAD, needs to delete */
786					dPrintf(D_M_RTMP, D_L_INFO,
787						("rtmp_timeout: Bad State for %d-%d (e#%d): remove\n",
788							en->NetStart, en->NetStop, i));
789#ifdef AURP_SUPPORT
790				if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
791					ddp_AURPsendx(AURPCODE_RTUPDATE,
792						(void *)en, AURPEV_NetDeleted);
793#endif
794
795					/* then clear the bit in the table concerning this entry.
796					If the zone Count reaches zero, remove the entry */
797
798					zt_remove_zones(en->ZoneBitMap);
799
800					RT_DELETE(en->NetStop, en->NetStart);
801				}
802				else {
803					en->EntryState = (en->EntryState & 0xF0) | state;
804					dPrintf(D_M_RTMP, D_L_INFO, ("Change State for %d-%d to %d (e#%d)\n",
805							en->NetStart, en->NetStop, state, i));
806				}
807			}
808		}
809		timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ);
810
811		atalk_unlock();
812}
813
814/*
815 * rtmp_prep_new_packet: allocate a ddp packet for RTMP use (reply to a RTMP request or
816 *                  Route Data Request, or generation of RTMP data packets.
817 *		    The ddp header is filled with relevant information, as well as
818 *                  the beginning of the rtmp packet with the following info:
819 *						Router's net number  (2bytes)
820 *						ID Length = 8		 (1byte)
821 *						Router's node ID	 (1byte)
822 *						Extended Range Start (2bytes)
823 *						Range + dist (0x80)  (1byte)
824 *						Extended Range End   (2bytes)
825 *						Rtmp version (0x82)  (1byte)
826 *
827 */
828
829gbuf_t *rtmp_prep_new_packet (at_ifaddr_t *, at_net, u_char, char);
830
831gbuf_t *rtmp_prep_new_packet (ifID, DstNet, DstNode, socket)
832register at_ifaddr_t        *ifID;
833register at_net DstNet;
834register u_char DstNode;
835register char socket;
836
837{
838	gbuf_t		*m;
839	register at_ddp_t	*ddp;
840	register char * rtmp_data;
841
842	if ((m = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
843		dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_new_packet: Can't allocate mblock\n"));
844		return ((gbuf_t *)NULL);
845	}
846
847	gbuf_rinc(m,AT_WR_OFFSET);
848	gbuf_wset(m,DDP_X_HDR_SIZE + 10);
849	ddp = (at_ddp_t *)(gbuf_rptr(m));
850
851	/*
852	 * Prepare the DDP header of the new packet
853	 */
854
855
856	ddp->unused = ddp->hopcount = 0;
857
858	UAS_ASSIGN(ddp->checksum, 0);
859
860	NET_NET(ddp->dst_net, DstNet);
861	ddp->dst_node =  DstNode;
862	ddp->dst_socket = socket;
863
864	NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
865	ddp->src_node = ifID->ifThisNode.s_node;
866	ddp->src_socket = RTMP_SOCKET;
867	ddp->type = DDP_RTMP;
868
869	/*
870	 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
871	 * (this works only if we are on an extended net)
872	 */
873
874	rtmp_data = ddp->data;
875
876	*rtmp_data++ = (ifID->ifThisNode.s_net & 0xff00) >> 8;
877	*rtmp_data++ = ifID->ifThisNode.s_net & 0x00ff ;
878	*rtmp_data++ = 8;
879	*rtmp_data++ = (u_char)ifID->ifThisNode.s_node;
880	*rtmp_data++ = (CableStart & 0xff00) >> 8;
881	*rtmp_data++ = CableStart & 0x00ff ;
882	*rtmp_data++ = 0x80;	/* first tuple, so distance is always zero */
883	*rtmp_data++ = (CableStop & 0xff00) >> 8;
884	*rtmp_data++ = CableStop & 0x00ff ;
885	*rtmp_data++ = RTMP_VERSION_NUMBER;
886
887	return (m);
888
889
890}
891int rtmp_r_find_bridge(at_ifaddr_t *, at_ddp_t *);
892
893int rtmp_r_find_bridge(ifID, orig_ddp)
894register at_ifaddr_t    *ifID;
895register at_ddp_t 	*orig_ddp;
896
897{
898	gbuf_t		*m;
899	register int		size, status;
900	register at_ddp_t	*ddp;
901	register char * rtmp_data;
902	RT_entry *Entry;
903
904
905	/* find the bridge for the querried net */
906
907	Entry = rt_blookup(NET_VALUE(orig_ddp->dst_net));
908
909	if (Entry == NULL) {
910		dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_r_find_bridge: no info for net %d\n",
911			 NET_VALUE(orig_ddp->dst_net)));
912		return (1);
913	}
914
915
916	size = DDP_X_HDR_SIZE + 10 ;
917	if ((m = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
918		dPrintf(D_M_RTMP, D_L_WARNING,
919			("rtmp_r_find_bridge: Can't allocate mblock\n"));
920		return (ENOBUFS);
921	}
922
923	gbuf_rinc(m,AT_WR_OFFSET);
924	gbuf_wset(m,size);
925	ddp = (at_ddp_t *)(gbuf_rptr(m));
926
927	/*
928	 * Prepare the DDP header of the new packet
929	 */
930
931	ddp->unused = ddp->hopcount = 0;
932
933	DDPLEN_ASSIGN(ddp, size);
934	UAS_ASSIGN(ddp->checksum, 0);
935
936	NET_NET(ddp->dst_net, orig_ddp->src_net);
937	ddp->dst_node =  orig_ddp->src_node;
938	ddp->dst_socket = orig_ddp->src_socket;
939
940	NET_ASSIGN(ddp->src_net, Entry->NextIRNet);
941	ddp->src_node = Entry->NextIRNode;
942	ddp->src_socket = RTMP_SOCKET;
943	ddp->type = DDP_RTMP;
944
945	/*
946	 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
947	 * (this works only if we are on an extended net)
948	 */
949
950	rtmp_data = ddp->data;
951
952	*rtmp_data++ = (Entry->NextIRNet & 0xff00) >> 8;
953	*rtmp_data++ = Entry->NextIRNet & 0x00ff ;
954	*rtmp_data++ = 8;
955	*rtmp_data++ = (u_char)Entry->NextIRNode;
956	*rtmp_data++ = (Entry->NetStart & 0xff00) >> 8;
957	*rtmp_data++ = Entry->NetStart & 0x00ff ;
958	*rtmp_data++ = 0x80;	/* first tuple, so distance is always zero */
959	*rtmp_data++ = (Entry->NetStop & 0xff00) >> 8;
960	*rtmp_data++ = Entry->NetStop & 0x00ff ;
961	*rtmp_data++ = RTMP_VERSION_NUMBER;
962
963
964	dPrintf(D_M_RTMP, D_L_INFO, ("rtmp_r_find_bridge: for net %d send back router %d.%d\n",
965				NET_VALUE(orig_ddp->dst_net), Entry->NextIRNet, Entry->NextIRNode));
966	if ((status = ddp_router_output(m, ifID, AT_ADDR, NET_VALUE(orig_ddp->src_net),
967			orig_ddp->src_node, 0))){
968		dPrintf(D_M_RTMP, D_L_WARNING,
969			("rtmp_r_find_bridge: ddp_router_output failed status=%d\n", status));
970				return (status);
971	}
972	return (0);
973}
974
975/*
976 * rtmp_send_table:
977 *	Send the routing table entries in RTMP data packets.
978 *	Use split horizon if specified. The Data packets are sent
979 *	as full DDP packets, if the last packet is full an empty
980 *	packet is sent to tell the recipients that this is the end of
981 *	the table...
982 *
983 */
984static int rtmp_send_table(at_ifaddr_t *, at_net, u_char, short, char, short);
985
986static int rtmp_send_table(ifID, DestNet, DestNode, split_hz, socket,
987			   n_neighbors)
988     register at_ifaddr_t *ifID;	/* interface/port params */
989     register at_net 	DestNet;	/* net where to send the table */
990     register u_char 	DestNode;	/* node where to send to table */
991     short 		split_hz;	/* use split horizon */
992     char		socket;		/* the destination socket to send to */
993     short 		n_neighbors;	/* used to send packets telling we are going down */
994{
995
996	RT_entry *Entry;
997	char *Buff_ptr;
998	u_char NewDist;
999	gbuf_t *m;
1000	short size,status ;
1001	register at_ddp_t	*ddp;
1002	register short EntNb = 0, sent_tuple = 0;
1003
1004	if (ifID->ifRoutingState < PORT_ONLINE) {
1005		dPrintf(D_M_RTMP, D_L_INFO,
1006			("rtmp_send_table: port %d activating, we don't send anything!\n",
1007			 ifID->ifPort));
1008		return (0);
1009	}
1010
1011	/* prerare tuples and packets for DDP*/
1012	/* if split horizon, do not send tuples we can reach on the port we
1013	 * want to send too
1014	 */
1015
1016	Entry = &RT_table[0];
1017	size = 0;
1018	if (!(m = rtmp_prep_new_packet(ifID, DestNet, DestNode, socket))) {
1019		dPrintf(D_M_RTMP, D_L_WARNING,
1020			("rtmp_send_table: rtmp_prep_new_packet failed\n"));
1021		return(ENOBUFS);
1022	}
1023
1024	ddp = (at_ddp_t *)(gbuf_rptr(m));
1025	Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10);
1026
1027	while (EntNb < RT_maxentry) {
1028
1029		if (Entry->NetStop && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT)) {
1030			if (!(split_hz && ifID->ifPort == Entry->NetPort)) {
1031				sent_tuple++;
1032
1033				if (((Entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) || n_neighbors)
1034					NewDist = NOTIFY_N_DIST;
1035				else
1036					NewDist = Entry->NetDist & 0x1F;
1037
1038				if (Entry->NetStart) {	/* Extended */
1039					*Buff_ptr++ = (Entry->NetStart & 0xFF00) >> 8;
1040					*Buff_ptr++ = (Entry->NetStart & 0x00FF);
1041					*Buff_ptr++ = 0x80 | NewDist;
1042					*Buff_ptr++ = (Entry->NetStop & 0xFF00) >> 8;
1043					*Buff_ptr++ = (Entry->NetStop & 0x00FF);
1044					*Buff_ptr++ = RTMP_VERSION_NUMBER;
1045					size += 6;
1046				}
1047				else {	/* non extended tuple */
1048					*Buff_ptr++ = (Entry->NetStop & 0xFF00) >> 8;
1049					*Buff_ptr++ = (Entry->NetStop & 0x00FF);
1050					*Buff_ptr++ = NewDist;
1051					size += 3;
1052				}
1053			}
1054		}
1055
1056		if (size > (DDP_DATA_SIZE-20)) {
1057			DDPLEN_ASSIGN(ddp, (size + DDP_X_HDR_SIZE + 10));
1058			gbuf_winc(m,size);
1059			if ((status = ddp_router_output(m, ifID, AT_ADDR,
1060				NET_VALUE(DestNet),DestNode, 0))){
1061			  dPrintf(D_M_RTMP, D_L_WARNING,
1062				  ("rtmp_send_table: ddp_router_output failed status=%d\n",
1063				   status));
1064			  return (status);
1065			}
1066			if ((m = rtmp_prep_new_packet (ifID, DestNet, DestNode, socket)) == NULL){
1067				dPrintf(D_M_RTMP, D_L_WARNING,
1068					("rtmp_send_table: rtmp_prep_new_poacket failed status=%d\n",
1069					 status));
1070				return (ENOBUFS);
1071			}
1072			ddp = (at_ddp_t *)(gbuf_rptr(m));
1073			Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10);
1074
1075			dPrintf(D_M_RTMP_LOW, D_L_OUTPUT,
1076				("rtmp_s_tble: Send %d tuples on port %d\n",
1077				 sent_tuple, ifID->ifPort));
1078			sent_tuple = 0;
1079			size = 0;
1080		}
1081
1082		Entry++;
1083		EntNb++;
1084	}
1085
1086	/*
1087	 * If we have some remaining entries to send, send them now.
1088         * otherwise, the last packet we sent was full, we need to send an empty one
1089         */
1090
1091	DDPLEN_ASSIGN(ddp, (size + DDP_X_HDR_SIZE + 10));
1092	gbuf_winc(m,size);
1093	if ((status =
1094	     ddp_router_output(m, ifID, AT_ADDR, NET_VALUE(DestNet),DestNode, 0))){
1095		dPrintf(D_M_RTMP, D_L_WARNING,
1096		("rtmp_send_table: ddp_router_output failed status=%d\n", status));
1097		return (status);
1098	}
1099	dPrintf(D_M_RTMP_LOW, D_L_OUTPUT,
1100		("rtmp_s_tble: LAST Packet split=%d with %d tuples sent on port %d\n",
1101		split_hz, sent_tuple, ifID->ifPort));
1102
1103	return (0);
1104}
1105
1106/*
1107 * rtmp_request: respond to the 3 types of RTMP requests RTMP may receive
1108 *      RTMP func =1 : respond with an RTMP Reponse Packet
1109 *	RTMP func =2 : respond with the routing table RTMP packet with split horizon
1110 *	RTMP func =3 : respond with the routing table RTMP packet no split horizon
1111 *
1112 * see Inside AppleTalk around page 5-18 for "details"
1113 */
1114
1115static void rtmp_request(ifID, ddp)
1116     register at_ifaddr_t *ifID;
1117     register at_ddp_t *ddp;
1118{
1119
1120	short split_horizon = FALSE;
1121	short code;
1122	short error;
1123
1124	/* We ignore the request if we're activating on that port */
1125
1126	if (ifID->ifRoutingState <  PORT_ONLINE)
1127			return;
1128
1129	/* check RTMP function code */
1130
1131	code = ddp->data[0];
1132
1133	switch (code) {
1134
1135		case RTMP_REQ_FUNC1:	/* RTMP Find Bridge */
1136
1137			/* RTMP Request Packet: we send a response with the next IRrange */
1138			dPrintf(D_M_RTMP, D_L_INPUT,
1139				( "rtmp_request: find bridge for net %d port %d node %d.%d\n",
1140				  NET_VALUE(ddp->dst_net), ifID->ifPort,
1141				  NET_VALUE(ddp->src_net), ddp->src_node));
1142
1143			if ((error = rtmp_r_find_bridge (ifID, ddp))) {
1144				dPrintf(D_M_RTMP, D_L_WARNING,
1145					("rtmp_request: Code 1 ddp_r_output failed error=%d\n",
1146					 error));
1147				return;
1148			}
1149
1150			break;
1151
1152		case RTMP_REQ_FUNC2:
1153
1154			split_horizon = TRUE;
1155
1156		case RTMP_REQ_FUNC3:
1157
1158			/* RTMP Route Request Packet */
1159
1160			dPrintf(D_M_RTMP, D_L_INPUT,
1161				("rtmp_request:  received code=%d from %d.%d for %d.%d\n",
1162				 code, NET_VALUE(ddp->src_net), ddp->src_node,
1163				 NET_VALUE(ddp->dst_net), ddp->dst_node));
1164
1165			rtmp_send_table(ifID, ddp->src_net, ddp->src_node,
1166					split_horizon, ddp->src_socket, 0);
1167
1168			break;
1169
1170		default:
1171
1172			/* unknown type of request */
1173		  dPrintf(D_M_RTMP, D_L_WARNING,
1174			  ("rtmp_request : invalid type of request =%d\n",
1175			   code));
1176		  break;
1177	}
1178
1179}
1180
1181/* locked version of rtmp_send_port */
1182void rtmp_send_port_locked(void *arg)
1183{
1184	at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
1185	atalk_lock();
1186	rtmp_send_port(ifID);
1187	atalk_unlock();
1188}
1189
1190
1191/*
1192 * rtmp_send_all_ports : send the routing table on all connected ports
1193 *                       check for the port status and if ok, send the
1194 *                       rtmp tuples to the broadcast address for the port
1195 *                       usually called on timeout every 10 seconds.
1196 */
1197
1198void rtmp_send_port(ifID)
1199     register at_ifaddr_t *ifID;
1200{
1201	at_net 	DestNet;
1202
1203	NET_ASSIGN(DestNet, 0);
1204
1205	if (ifID && ifID->ifRoutingState == PORT_ONLINE) {
1206		dPrintf(D_M_RTMP_LOW, D_L_OUTPUT,
1207			("rtmp_send_port: do stuff for port=%d\n",
1208			 ifID->ifPort));
1209		if (ifID->ifZipNeedQueries)
1210			zip_send_queries(ifID, 0, 0xFF);
1211		if (!ROUTING_MODE) {
1212			return;
1213                }
1214		rtmp_send_table(ifID, DestNet, 0xFF, 1, RTMP_SOCKET, 0);
1215	}
1216
1217#ifdef DEBUG
1218	if (ifID == ifID_home)
1219		dPrintf(D_M_RTMP_LOW, D_L_VERBOSE,
1220			("I:%5d O:%5d H:%5d dropped:%d\n",
1221			 pktsIn, pktsOut, pktsHome, pktsDropped));
1222
1223	dPrintf(D_M_RTMP_LOW, D_L_TRACE,
1224		("rtmp_send_port: func=0x%x, ifID=0x%x\n",
1225		 (u_int) rtmp_send_port, (u_int) ifID));
1226#endif
1227
1228	timeout (rtmp_send_port_locked, (caddr_t)ifID, 10 * SYS_HZ);
1229
1230}
1231
1232/* rtmp_dropper: check the number of packet received every x secondes.
1233 *               the actual packet dropping is done in ddp_input
1234 */
1235
1236void rtmp_dropper(__unused void *arg)
1237{
1238
1239	atalk_lock();
1240
1241	pktsIn = pktsOut = pktsHome = pktsDropped = 0;
1242	timeout(rtmp_dropper, NULL, 2*SYS_HZ);
1243
1244	atalk_unlock();
1245}
1246
1247/*
1248 * rtmp_router_start: perform the sanity checks before declaring the router up
1249 *	 and running. This function looks for discrepency between the net infos
1250 *	 for the different ports and seed problems.
1251 *	 If everything is fine, the state of each port is brought to PORT_ONLINE.\
1252 *   ### LD 01/09/95 Changed to correct Zone problem on non seed ports.
1253 */
1254
1255int rtmp_router_start(at_kern_err_t *keP)
1256{
1257	int err = 0;
1258	register at_ifaddr_t *ifID, *ifID2;
1259	register short Index, router_starting_timer = 0;
1260	register RT_entry *Entry;
1261	register at_net_al netStart, netStop;
1262	struct timespec ts;
1263
1264
1265	/* clear the static structure used to record routing errors */
1266	bzero(&ke, sizeof(ke));
1267
1268	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1269
1270		/* if non seed, need to acquire the right node address */
1271
1272		if ((ifID->ifFlags & RTR_SEED_PORT) == 0)  {
1273			if ((ifID->ifThisCableStart == 0 && ifID->ifThisCableEnd == 0) ||
1274				(ifID->ifThisCableStart >= DDP_STARTUP_LOW &&
1275				ifID->ifThisCableEnd <= DDP_STARTUP_HIGH))  {
1276
1277				if (ifID->ifThisCableEnd == 0)  {
1278					keP->error 	= KE_NO_SEED;
1279					keP->port1 	= ifID->ifPort;
1280					strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1281				}
1282				else {
1283					keP->error 	= KE_INVAL_RANGE;
1284					keP->port1 	= ifID->ifPort;
1285					strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1286					keP->netr1b 	= ifID->ifThisCableStart;
1287					keP->netr1e 	= ifID->ifThisCableEnd;
1288				}
1289				ifID->ifRoutingState = PORT_ERR_STARTUP;
1290				RouterError(ifID->ifPort, ERTR_CABLE_STARTUP);
1291
1292				goto error;
1293			}
1294
1295			/* we are non seed, so try to acquire the zones for that guy */
1296			ifID->ifZipNeedQueries = 1;
1297
1298			dPrintf(D_M_RTMP, D_L_STARTUP,
1299				("rtmp_router_start: call elap_online for Non Seed port #%d cable =%d-%d\n",
1300					ifID->ifPort, CableStart, CableStop));
1301			if ((err = elap_online3(ifID)))
1302				goto error;
1303		}
1304	}
1305
1306	/* Check if we have a problem with the routing table size */
1307
1308	if (ErrorRTMPoverflow) {
1309		keP->error = KE_RTMP_OVERFLOW;
1310		goto error;
1311	}
1312
1313
1314	/* Now, check that we don't have a conflict in between our interfaces */
1315	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1316
1317		/* check if the RoutingState != PORT_ONERROR */
1318		if (ifID->ifRoutingState < PORT_ACTIVATING) {
1319			goto error;
1320		}
1321
1322		if ((ifID->ifThisCableStart == 0 && ifID->ifThisCableEnd == 0) ||
1323			(ifID->ifThisCableStart >= DDP_STARTUP_LOW &&
1324			ifID->ifThisCableEnd <= DDP_STARTUP_HIGH))  {
1325
1326			if (ifID->ifThisCableEnd == 0)  {
1327				keP->error 	= KE_NO_SEED;
1328				keP->port1 	= ifID->ifPort;
1329				strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1330			}
1331			else {
1332				keP->error 	= KE_INVAL_RANGE;
1333				keP->port1 	= ifID->ifPort;
1334				strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1335				keP->netr1b 	= ifID->ifThisCableStart;
1336				keP->netr1e 	= ifID->ifThisCableEnd;
1337			}
1338
1339			ifID->ifRoutingState = PORT_ERR_STARTUP;
1340			RouterError(ifID->ifPort, ERTR_CABLE_STARTUP);
1341
1342			goto error;
1343		}
1344
1345			/* check the interface address against all other ifs */
1346
1347		netStart = ifID->ifThisCableStart;
1348		netStop = ifID->ifThisCableEnd;
1349
1350		for (ifID2 = TAILQ_NEXT(ifID, aa_link); ifID2;
1351		     ifID2 = TAILQ_NEXT(ifID2, aa_link)) {
1352
1353			if (((netStart >= ifID2->ifThisCableStart) &&
1354				(netStart <= ifID2->ifThisCableEnd)) ||
1355			    ((netStop >= ifID2->ifThisCableStart) &&
1356				(netStop <= ifID2->ifThisCableEnd)) ||
1357				((ifID2->ifThisCableStart >= netStart) &&
1358				(ifID2->ifThisCableStart <= netStop)) ||
1359				((ifID2->ifThisCableEnd >= netStart) &&
1360				(ifID2->ifThisCableEnd <= netStop)) ) {
1361
1362					keP->error 	= KE_CONF_RANGE;
1363					keP->port1 	= ifID->ifPort;
1364					strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1365					keP->port2 	= ifID2->ifPort;
1366					strlcpy(keP->name2, ifID2->ifName,sizeof(keP->name2));
1367					keP->netr1b 	= ifID->ifThisCableStart;
1368					keP->netr1e 	= ifID->ifThisCableEnd;
1369					ifID->ifRoutingState = PORT_ERR_CABLER;
1370					RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT);
1371					goto error;
1372			}
1373
1374		}
1375
1376		/* ### LD 01/04/94: We need to fill in the next IR info in the routing table */
1377		Entry = rt_blookup(ifID->ifThisCableEnd);
1378
1379		if (Entry == NULL) {
1380			dPrintf(D_M_RTMP, D_L_ERROR,
1381				("rtmp_router_start: we don't know our cable range port=%d\n",
1382			ifID->ifPort));
1383
1384			goto error;
1385		}
1386
1387		/*
1388		 * Note: At this point, non seed ports may not be aware of their Default zone
1389		 */
1390
1391		if (!(ifID->ifFlags & RTR_SEED_PORT)) {
1392			ifID->ifDefZone = 0;
1393			Entry->EntryState |= (RTE_STATE_GOOD|RTE_STATE_UPDATED);
1394		}
1395
1396		ifID->ifRoutingState = PORT_ONLINE;
1397		ifID->ifState = LAP_ONLINE;
1398
1399		/* set the right net and node for each port */
1400		Entry->NextIRNet = ifID->ifThisNode.s_net;
1401		Entry->NextIRNode= ifID->ifThisNode.s_node;
1402
1403		dPrintf(D_M_RTMP, D_L_STARTUP,
1404			("rtmp_router_start: bring port=%d [%d.%d]... on line\n",
1405			 ifID->ifPort, ifID->ifThisNode.s_net,
1406			 ifID->ifThisNode.s_node));
1407
1408	}
1409
1410	/*
1411	 * Everything is fine, we can begin to babble on the net...
1412	 */
1413
1414	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1415		if (ifID->ifRoutingState == PORT_ONLINE)  {
1416			rtmp_send_port(ifID);
1417			timeout(rtmp_timeout, (caddr_t)ifID, (50+ifID->ifPort) * SYS_HZ);
1418			if (ifID->ifRoutingState  < PORT_ACTIVATING) {
1419				goto error;
1420			}
1421		}
1422	}
1423
1424	/* Check if we have a problem with the routing or zip table size */
1425
1426	if (ErrorRTMPoverflow) {
1427		keP->error = KE_RTMP_OVERFLOW;
1428		goto error;
1429	}
1430	if (ErrorZIPoverflow) {
1431		keP->error = KE_ZIP_OVERFLOW;
1432		goto error;
1433	}
1434
1435	/* sleep for 11 seconds */
1436	ts.tv_sec = 11;
1437	ts.tv_nsec = 0;
1438	if ((err =
1439	     /* *** eventually this will be the ifID for the interface
1440		being brought up in router mode *** */
1441	     /* *** router sends rtmp packets every 10 seconds *** */
1442		msleep(&ifID_home->startup_inprogress, atalk_mutex,
1443		    PSOCK | PCATCH, "router_start1", &ts))
1444	    != EWOULDBLOCK) {
1445		goto error;
1446	}
1447
1448	/* Is the stack still up ? */
1449	if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) {
1450		err = ECONNABORTED;
1451		goto error;
1452	}
1453
1454startZoneInfo:
1455	err = 0;
1456	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1457
1458		if (ifID->ifRoutingState < PORT_ACTIVATING) {
1459			goto error;
1460		}
1461
1462		if ((ifID->ifZipNeedQueries)
1463		 && (ifID->ifFlags & RTR_SEED_PORT) == 0)  {
1464			dPrintf(D_M_RTMP, D_L_STARTUP,
1465				("rtmp_router_start: send Zip Queries for Port %d\n",
1466					ifID->ifPort));
1467			zip_send_queries(ifID, 0, 0xFF);
1468
1469			if (router_starting_timer >= 10) {
1470				dPrintf(D_M_RTMP, D_L_WARNING,
1471					("rtmp_router_start: no received response to ZipNeedQueries\n"));
1472				keP->error 	= KE_NO_ZONES_FOUND;
1473				keP->port1 	= ifID->ifPort;
1474				strlcpy(keP->name1, ifID->ifName,sizeof(keP->name1));
1475				keP->netr1b 	= ifID->ifThisCableStart;
1476				keP->netr1e 	= ifID->ifThisCableEnd;
1477				ifID->ifRoutingState = PORT_ERR_CABLER;
1478				RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT);
1479				goto error;
1480			}
1481
1482			dPrintf(D_M_RTMP, D_L_STARTUP,
1483				("rtmp_router_start: waiting for zone info to complete\n"));
1484			/* sleep for 10 seconds */
1485			ts.tv_sec = 10;
1486			ts.tv_nsec = 0;
1487			if ((err =
1488			     /* *** eventually this will be the ifID for the
1489				    interface being brought up in router mode *** */
1490				msleep(&ifID_home->startup_inprogress, atalk_mutex,
1491				    PSOCK | PCATCH, "router_start2", &ts))
1492			    != EWOULDBLOCK) {
1493				goto error;
1494			}
1495
1496			/* Is the stack still up ? */
1497			if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) {
1498				err = ECONNABORTED;
1499				goto error;
1500			}
1501
1502			err = 0;
1503			router_starting_timer++;
1504			goto startZoneInfo;
1505		}
1506
1507	}
1508
1509	/* At This Point, check if we know the default zones for non seed port */
1510
1511	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1512
1513		if (ifID->ifRoutingState < PORT_ACTIVATING)
1514			goto error;
1515
1516		if (!(ifID->ifFlags & RTR_SEED_PORT)) {
1517			Entry = rt_blookup(ifID->ifThisCableEnd);
1518
1519			if (Entry == NULL) {
1520				dPrintf(D_M_RTMP, D_L_ERROR,
1521					("rtmp_router_start: (2)we don't know our cable range port=%d\n",
1522					ifID->ifPort));
1523				goto error;
1524			}
1525
1526			dPrintf(D_M_RTMP, D_L_STARTUP,
1527				("rtmp_router_start: if %s set to permanent\n",
1528				 ifID->ifName));
1529			Entry->NetDist = 0; 	/* added 4-29-96 jjs, prevent direct
1530						   nets from showing non-zero
1531						   distance */
1532			/* upgrade the non seed ports. */
1533			Entry->EntryState |= RTE_STATE_PERMANENT;
1534
1535			Index = zt_ent_zindex(Entry->ZoneBitMap);
1536			if (Index <= 0) {
1537				dPrintf(D_M_RTMP, D_L_ERROR,
1538					 ("rtmp_router_start: still don't know default zone for port %d\n",
1539					ifID->ifPort));
1540			} else {
1541				ifID->ifDefZone = Index;
1542				if ((ifID == ifID_home) || MULTIHOME_MODE) {
1543					ifID->ifZoneName = ZT_table[Index-1].Zone;
1544					(void)regDefaultZone(ifID);
1545
1546					/* Send zone change event */
1547					atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
1548				}
1549			}
1550		}
1551	}
1552
1553	/* Check if we have a problem with the routing or zip table size */
1554
1555	if (ErrorRTMPoverflow) {
1556		keP->error = KE_RTMP_OVERFLOW;
1557		goto error;
1558	}
1559	if (ErrorZIPoverflow) {
1560		keP->error = KE_ZIP_OVERFLOW;
1561		goto error;
1562	}
1563
1564	/*
1565	 * Handle the Home Port specifics
1566	 */
1567
1568	/* set the router address as being us no matter what*/
1569	ifID_home->ifARouter = ifID_home->ifThisNode;
1570	ifID_home->ifRouterState = ROUTER_UPDATED;
1571
1572	/* prepare the packet dropper timer */
1573	timeout (rtmp_dropper, NULL, 1*SYS_HZ);
1574
1575	return(0);
1576
1577error:
1578	dPrintf(D_M_RTMP,D_L_ERROR,
1579		("rtmp_router_start: error type=%d occurred on port %d\n",
1580		ifID->ifRoutingState, ifID->ifPort));
1581
1582	/* if there's no keP->error, copy the local ke structure,
1583	   since the error occurred asyncronously */
1584	if ((!keP->error) && ke.error)
1585		bcopy(&ke, keP, sizeof(ke));
1586	rtmp_shutdown();
1587
1588	/* to return the error in keP, the ioctl has to return 0 */
1589
1590	return((keP->error)? 0: err);
1591} /* rtmp_router_start */
1592
1593void rtmp_router_start_tmo(void *arg)
1594{
1595	(void)rtmp_router_start_tmo((at_kern_err_t*)arg);
1596}
1597
1598void rtmp_shutdown(void)
1599{
1600	register at_ifaddr_t *ifID;
1601	at_net DestNet;
1602
1603	NET_ASSIGN(DestNet, 0);
1604
1605	dPrintf(D_M_RTMP, D_L_SHUTDN,
1606		("rtmp_shutdown:stop sending to all ports\n"));
1607
1608	untimeout(rtmp_dropper, (void *)0);
1609	untimeout(rtmp_router_start_tmo, (void *)1); /* added for 2225395 */
1610	untimeout(rtmp_router_start_tmo, (void *)3); /* added for 2225395 */
1611
1612	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1613		if (ifID->ifRoutingState > PORT_OFFLINE ) {
1614			if (ifID->ifRoutingState == PORT_ONLINE)  {
1615				untimeout(rtmp_send_port_locked, (caddr_t)ifID);
1616				untimeout(rtmp_timeout, (caddr_t) ifID);
1617			}
1618			/*
1619			 * it's better to notify the neighbour routers that we are going down
1620			 */
1621			if (ROUTING_MODE)
1622				rtmp_send_table(ifID, DestNet, 0xFF, TRUE,
1623						RTMP_SOCKET, TRUE);
1624
1625			ifID->ifRoutingState = PORT_OFFLINE;
1626
1627			dPrintf(D_M_RTMP, D_L_SHUTDN,
1628				("rtmp_shutdown: routing on port=%d... off line\nStats:\n",
1629				 ifID->ifPort));
1630			dPrintf(D_M_RTMP, D_L_SHUTDN,
1631			 ("fwdBytes     : %ld\nfwdPackets   : %ld\ndroppedBytes : %ld\ndroppedPkts  : %ld\n",
1632			ifID->ifStatistics.fwdBytes, ifID->ifStatistics.fwdPkts,
1633			ifID->ifStatistics.droppedBytes, ifID->ifStatistics.droppedPkts));
1634
1635		}
1636	}
1637
1638}
1639
1640/*
1641 * Remove all entries associated with the specified port.
1642 */
1643void rtmp_purge(ifID)
1644	at_ifaddr_t *ifID;
1645{
1646	u_char state;
1647	int i;
1648	RT_entry *en = &RT_table[0];
1649
1650	for (i=0; i < RT_maxentry; i++) {
1651		state = en->EntryState & 0x0F;
1652		if ((state > RTE_STATE_UNUSED) && (state != RTE_STATE_PERMANENT)
1653			&& en->NetStop && en->NetDist && (en->NetPort == ifID->ifPort)) {
1654			zt_remove_zones(en->ZoneBitMap);
1655			RT_DELETE(en->NetStop, en->NetStart);
1656		}
1657		en++;
1658	}
1659}
1660