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