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