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