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