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