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