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