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