]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/ddp_r_rtmp.c
2 * Copyright (c) 1994, 1996-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /*--------------------------------------------------------------------------
29 * Router RTMP protocol functions:
31 * This file contains Routing specifics to handle RTMP packets and
32 * the maintenance of the routing table through....
34 * The entry point for the rtmp input in ddp is valid only when we're
35 * running in router mode.
38 * 0.01 03/22/94 Laurent Dumont Creation
39 * Modified for MP, 1996 by Tuyen Nguyen
40 * Added AURP support, April 8, 1996 by Tuyen Nguyen
41 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
43 *-------------------------------------------------------------------------
46 #include <sys/errno.h>
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <machine/spl.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
53 #include <sys/filedesc.h>
54 #include <sys/fcntl.h>
56 #include <sys/ioctl.h>
57 #include <sys/malloc.h>
58 #include <kern/locks.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
64 #include <netat/sysglue.h>
65 #include <netat/appletalk.h>
66 #include <netat/at_pcb.h>
67 #include <netat/at_var.h>
68 #include <netat/ddp.h>
69 #include <netat/rtmp.h>
70 #include <netat/zip.h>
71 #include <netat/routing_tables.h>
72 #include <netat/aurp.h>
73 #include <netat/debug.h>
75 #include <sys/kern_event.h>
77 extern void (*ddp_AURPsendx
)(void);
78 extern at_ifaddr_t
*aurp_ifID
;
79 extern at_ifaddr_t
*ifID_table
[];
80 extern at_ifaddr_t
*ifID_home
;
83 int rtmp_router_start(at_kern_err_t
*);
84 void rtmp_router_start_tmo(void *);
88 static at_kern_err_t ke
;
89 /* Used to record error discovered in rtmp_update() */
91 void rtmp_timeout(void *arg
);
92 void rtmp_send_port(at_ifaddr_t
*);
93 void rtmp_send_port_locked(void *);
94 void rtmp_dropper(void *);
95 static void rtmp_update(at_ifaddr_t
*, at_rtmp
*, short);
96 static void rtmp_request(at_ifaddr_t
*, at_ddp_t
*);
97 int elap_online3(at_ifaddr_t
*);
99 extern short ErrorRTMPoverflow
, ErrorZIPoverflow
;
100 extern lck_mtx_t
* atalk_mutex
;
102 extern int pktsIn
, pktsOut
, pktsDropped
, pktsHome
;
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.
112 void rtmp_router_input(mp
, ifID
)
114 register at_ifaddr_t
*ifID
;
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. */
120 register at_net_al OurNet
;
121 register at_node OurNode
;
122 register at_net_al DstNet
;
123 register at_node DstNode
;
127 if (!ifID
|| (ifID
->ifRoutingState
< PORT_ACTIVATING
)) {
133 OurNet
= ifID
->ifThisNode
.s_net
;
134 OurNode
= ifID
->ifThisNode
.s_node
;
137 if (gbuf_type(mp
) != MSG_DATA
) {
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
143 dPrintf(D_M_RTMP
, D_L_WARNING
,
144 ("rtmp_router_input: Not an M_DATA type\n"));
149 DstNet
= NET_VALUE(ddp
->dst_net
);
150 DstNode
= ddp
->dst_node
;
152 /* check the kind of RTMP packet we received */
158 tuples
= gbuf_len(mp
) - DDP_X_HDR_SIZE
- RTMP_IDLENGTH
;
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
168 if (tuples
% 3) {/* not a valid RTMP data packet */
170 dPrintf(D_M_RTMP
, D_L_WARNING
,
171 ("rtmp_input: bad number of tuple in RTMP packet\n"));
177 rtmp_update(ifID
, (at_rtmp
*)ddp
->data
, tuples
);
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.
194 if (DstNode
== 255) {
195 if (((DstNet
>= CableStart
) && (DstNet
<= CableStop
)) ||
197 rtmp_request(ifID
, ddp
);
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
);
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
);
223 if ((DstNode
== OurNode
) && (DstNet
== OurNet
)) {
224 rtmp_request(ifID
, ddp
);
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
);
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
);
246 } /* rtmp_router_input */
253 static void rtmp_update(ifID
, rtmp
, tuple_nb
)
254 register at_ifaddr_t
*ifID
;
255 register at_rtmp
*rtmp
;
256 register short tuple_nb
;
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 register u_char SenderNodeID
= rtmp
->at_rtmp_id
[0];
266 bzero(&NewRoute
, sizeof(RT_entry
));
268 /* Make sure this an AppleTalk node sending us the RTMP packet */
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
));
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.
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 strlcpy(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
);
301 CableStart
= TUPLENET(FirstTuple
);
302 CableStop
= TUPLENET(SecondTuple
);
304 dPrintf(D_M_RTMP, D_L_INFO,
305 ("rtmp_update: Port #%d activating, set Cable %d-%d\n",
306 ifID->ifPort, CableStart, CableStop));
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 strlcpy(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
);
322 CableStop
= NET_VALUE(rtmp
->at_rtmp_this_net
);
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
));
331 * Perform a few sanity checks on the received RTMP data packet
334 if ((PortFlags
& RTR_XNET_PORT
) && (tuple_nb
>= 2)) {
336 /* The first tuple must be extended */
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
)));
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 strlcpy(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
);
363 /* check that the tuple matches the range */
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
)) {
372 * IS THIS NON-FATAL?????
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 strlcpy(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
);
387 if (TUPLEDIST(FirstTuple
) != 0) {
388 dPrintf(D_M_RTMP
, D_L_WARNING
,
389 ("rtmp_update: Invalid distance in 1st tuple\n"));
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]));
401 else { /* non extended interface or problem in tuple*/
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"));
409 if (TUPLENET(FirstTuple
) == 0) { /* non extended RTMP data */
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"));
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
);
431 NewRoute
.NextIRNet
= NET_VALUE(rtmp
->at_rtmp_this_net
);
432 NewRoute
.NextIRNode
= SenderNodeID
;
433 NewRoute
.NetPort
= ifID
->ifPort
;
436 * Process the case where a non-seed port needs to acquire the right
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
)));
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
);
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
);
460 * Now, check if we already know this route, or we need to add it
461 * (or modify it in the table accordingly)
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... */
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 */
478 if (CurrentRoute
->EntryState
& RTE_STATE_UPDATED
) {
479 CurrentRoute
->EntryState
&= ~RTE_STATE_UPDATED
;
482 state
= state
>> 1 ; /* decrement state */
485 CurrentRoute
->EntryState
= (CurrentRoute
->EntryState
& 0xF0) | state
;
489 else { /* add the new route */
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
));
495 NewRoute
.EntryState
= RTE_STATE_GOOD
|RTE_STATE_UPDATED
;
496 NewRoute
.NetDist
= 0;
498 if (rt_insert(NewRoute
.NetStop
, NewRoute
.NetStart
, 0,
499 0, NewRoute
.NetDist
, NewRoute
.NetPort
,
500 NewRoute
.EntryState
) == (RT_entry
*)NULL
)
502 ErrorRTMPoverflow
= 1;
507 if (ifID
->ifRoutingState
== PORT_ACTIVATING
) {
508 dPrintf(D_M_RTMP
, D_L_INFO
,
509 ("rtmp_update: port activating, ignoring remaining tuples\n"));
514 * Process all the tuples against our routing table
517 TuplePtr
= (char *)FirstTuple
;
519 while (tuple_nb
-- > 0) {
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",
525 NewRoute
.NetDist
= NOTIFY_N_DIST
;
526 NewRoute
.EntryState
= RTE_STATE_BAD
;
529 NewRoute
.NetDist
= TUPLEDIST(TuplePtr
) + 1;
530 NewRoute
.EntryState
= RTE_STATE_GOOD
;
531 NewRoute
.EntryState
= RTE_STATE_GOOD
|RTE_STATE_UPDATED
;
535 if (TUPLERANGE(TuplePtr
)) { /* Extended Tuple */
538 NewRoute
.NetStart
= TUPLENET(TuplePtr
);
540 NewRoute
.NetStop
= TUPLENET((TuplePtr
));
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
)) {
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
));
559 else { /* Non Extended Tuple */
561 NewRoute
.NetStart
= 0;
562 NewRoute
.NetStop
= TUPLENET(TuplePtr
);
566 if ((NewRoute
.NetDist
== 0) ||
567 (NewRoute
.NetStop
== 0) ||
568 (NewRoute
.NetStop
>= DDP_STARTUP_LOW
)) {
570 dPrintf(D_M_RTMP
, D_L_WARNING
,
571 ("rtmp_update: P# %d, non valid tuple received [%d]\n",
572 ifID
->ifPort
, NewRoute
.NetStop
));
578 if ((CurrentRoute
= rt_blookup(NewRoute
.NetStop
))) {
579 /* found something... */
581 if (NewRoute
.NetDist
< 16 ||
582 NewRoute
.NetDist
== NOTIFY_N_DIST
) {
585 * Check if the definition of the route changed
588 if (NewRoute
.NetStop
!= CurrentRoute
->NetStop
||
589 NewRoute
.NetStart
!= CurrentRoute
->NetStart
) {
591 if (NewRoute
.NetStop
== CurrentRoute
->NetStop
&&
592 NewRoute
.NetStop
== CurrentRoute
->NetStart
&&
593 NewRoute
.NetStart
== 0)
595 NewRoute
.NetStart
= NewRoute
.NetStop
;
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;
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
;
619 * If we don't know the associated zones
622 if (!RT_ALL_ZONES_KNOWN(CurrentRoute
)) {
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
));
629 /* set the flag in the ifID structure telling
630 * that a scheduling of Zip Query is needed.
633 ifID
->ifZipNeedQueries
= 1;
637 if (((CurrentRoute
->EntryState
& 0x0F) <= RTE_STATE_SUSPECT
) &&
638 NewRoute
.NetDist
!= NOTIFY_N_DIST
) {
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)));
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
);
658 if (NewRoute
.NetDist
== NOTIFY_N_DIST
) {
660 CurrentRoute
->EntryState
=
661 (CurrentRoute
->EntryState
& 0xF0) | RTE_STATE_SUSPECT
;
662 CurrentRoute
->NetDist
= NOTIFY_N_DIST
;
670 if ((NewRoute
.NetDist
<= CurrentRoute
->NetDist
) && (NewRoute
.NetDist
<16)) {
672 /* Found a shorter or more recent Route,
673 * Replace with the New entryi
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
;
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
));
688 if (ddp_AURPsendx
&& (aurp_ifID
->ifFlags
& AT_IFF_AURP
))
689 ddp_AURPsendx(AURPCODE_RTUPDATE
,
690 (void *)&NewRoute
, AURPEV_NetDistChange
);
694 else { /* no entry found */
696 if (NewRoute
.NetDist
< 16 && NewRoute
.NetDist
!= NOTIFY_N_DIST
&&
697 NewRoute
.NextIRNet
>= ifID
->ifThisCableStart
&&
698 NewRoute
.NextIRNet
<= ifID
->ifThisCableEnd
) {
700 NewRoute
.EntryState
= (RTE_STATE_GOOD
|RTE_STATE_UPDATED
);
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
));
706 ifID
->ifZipNeedQueries
= 1;
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;
713 else if (ddp_AURPsendx
&& (aurp_ifID
->ifFlags
& AT_IFF_AURP
))
714 ddp_AURPsendx(AURPCODE_RTUPDATE
,
715 (void *)&NewRoute
, AURPEV_NetAdded
);
720 } /* end of main while */
721 ifID
->ifRouterState
= ROUTER_UPDATED
;
722 if (ifID
->ifZipNeedQueries
)
723 zip_send_queries(ifID
, 0, 0xFF);
726 timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ);
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
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
747 void rtmp_timeout(void *arg
)
749 at_ifaddr_t
*ifID
= (at_ifaddr_t
*)arg
;
750 register u_char state
;
752 RT_entry
*en
= &RT_table
[0];
756 if (ifID
->ifRoutingState
< PORT_ONLINE
) {
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
--;
766 for (i
= 0 ; i
< RT_maxentry
; i
++,en
++) {
768 /* we want to age "learned" nets, not directly connected ones */
769 state
= en
->EntryState
& 0x0F;
772 if (state
> RTE_STATE_UNUSED
&&
773 !(en
->EntryState
& RTE_STATE_PERMANENT
) && en
->NetStop
&&
774 en
->NetDist
&& en
->NetPort
== ifID
->ifPort
) {
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
;
783 state
= state
>> 1 ; /* decrement state */
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
));
790 if (ddp_AURPsendx
&& (aurp_ifID
->ifFlags
& AT_IFF_AURP
))
791 ddp_AURPsendx(AURPCODE_RTUPDATE
,
792 (void *)en
, AURPEV_NetDeleted
);
795 /* then clear the bit in the table concerning this entry.
796 If the zone Count reaches zero, remove the entry */
798 zt_remove_zones(en
->ZoneBitMap
);
800 RT_DELETE(en
->NetStop
, en
->NetStart
);
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
));
809 timeout(rtmp_timeout
, (caddr_t
) ifID
, 20*SYS_HZ
);
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)
829 gbuf_t
*rtmp_prep_new_packet (at_ifaddr_t
*, at_net
, u_char
, char);
831 gbuf_t
*rtmp_prep_new_packet (ifID
, DstNet
, DstNode
, socket
)
832 register at_ifaddr_t
*ifID
;
833 register at_net DstNet
;
834 register u_char DstNode
;
835 register char socket
;
839 register at_ddp_t
*ddp
;
840 register char * rtmp_data
;
842 if ((m
= gbuf_alloc(AT_WR_OFFSET
+1024, PRI_HI
)) == NULL
) {
843 dPrintf(D_M_RTMP
, D_L_WARNING
, ("rtmp_new_packet: Can't allocate mblock\n"));
844 return ((gbuf_t
*)NULL
);
847 gbuf_rinc(m
,AT_WR_OFFSET
);
848 gbuf_wset(m
,DDP_X_HDR_SIZE
+ 10);
849 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
852 * Prepare the DDP header of the new packet
856 ddp
->unused
= ddp
->hopcount
= 0;
858 UAS_ASSIGN(ddp
->checksum
, 0);
860 NET_NET(ddp
->dst_net
, DstNet
);
861 ddp
->dst_node
= DstNode
;
862 ddp
->dst_socket
= socket
;
864 NET_ASSIGN(ddp
->src_net
, ifID
->ifThisNode
.s_net
);
865 ddp
->src_node
= ifID
->ifThisNode
.s_node
;
866 ddp
->src_socket
= RTMP_SOCKET
;
867 ddp
->type
= DDP_RTMP
;
870 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
871 * (this works only if we are on an extended net)
874 rtmp_data
= ddp
->data
;
876 *rtmp_data
++ = (ifID
->ifThisNode
.s_net
& 0xff00) >> 8;
877 *rtmp_data
++ = ifID
->ifThisNode
.s_net
& 0x00ff ;
879 *rtmp_data
++ = (u_char
)ifID
->ifThisNode
.s_node
;
880 *rtmp_data
++ = (CableStart
& 0xff00) >> 8;
881 *rtmp_data
++ = CableStart
& 0x00ff ;
882 *rtmp_data
++ = 0x80; /* first tuple, so distance is always zero */
883 *rtmp_data
++ = (CableStop
& 0xff00) >> 8;
884 *rtmp_data
++ = CableStop
& 0x00ff ;
885 *rtmp_data
++ = RTMP_VERSION_NUMBER
;
891 int rtmp_r_find_bridge(at_ifaddr_t
*, at_ddp_t
*);
893 int rtmp_r_find_bridge(ifID
, orig_ddp
)
894 register at_ifaddr_t
*ifID
;
895 register at_ddp_t
*orig_ddp
;
899 register int size
, status
;
900 register at_ddp_t
*ddp
;
901 register char * rtmp_data
;
905 /* find the bridge for the querried net */
907 Entry
= rt_blookup(NET_VALUE(orig_ddp
->dst_net
));
910 dPrintf(D_M_RTMP
, D_L_WARNING
, ("rtmp_r_find_bridge: no info for net %d\n",
911 NET_VALUE(orig_ddp
->dst_net
)));
916 size
= DDP_X_HDR_SIZE
+ 10 ;
917 if ((m
= gbuf_alloc(AT_WR_OFFSET
+size
, PRI_HI
)) == NULL
) {
918 dPrintf(D_M_RTMP
, D_L_WARNING
,
919 ("rtmp_r_find_bridge: Can't allocate mblock\n"));
923 gbuf_rinc(m
,AT_WR_OFFSET
);
925 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
928 * Prepare the DDP header of the new packet
931 ddp
->unused
= ddp
->hopcount
= 0;
933 DDPLEN_ASSIGN(ddp
, size
);
934 UAS_ASSIGN(ddp
->checksum
, 0);
936 NET_NET(ddp
->dst_net
, orig_ddp
->src_net
);
937 ddp
->dst_node
= orig_ddp
->src_node
;
938 ddp
->dst_socket
= orig_ddp
->src_socket
;
940 NET_ASSIGN(ddp
->src_net
, Entry
->NextIRNet
);
941 ddp
->src_node
= Entry
->NextIRNode
;
942 ddp
->src_socket
= RTMP_SOCKET
;
943 ddp
->type
= DDP_RTMP
;
946 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
947 * (this works only if we are on an extended net)
950 rtmp_data
= ddp
->data
;
952 *rtmp_data
++ = (Entry
->NextIRNet
& 0xff00) >> 8;
953 *rtmp_data
++ = Entry
->NextIRNet
& 0x00ff ;
955 *rtmp_data
++ = (u_char
)Entry
->NextIRNode
;
956 *rtmp_data
++ = (Entry
->NetStart
& 0xff00) >> 8;
957 *rtmp_data
++ = Entry
->NetStart
& 0x00ff ;
958 *rtmp_data
++ = 0x80; /* first tuple, so distance is always zero */
959 *rtmp_data
++ = (Entry
->NetStop
& 0xff00) >> 8;
960 *rtmp_data
++ = Entry
->NetStop
& 0x00ff ;
961 *rtmp_data
++ = RTMP_VERSION_NUMBER
;
964 dPrintf(D_M_RTMP
, D_L_INFO
, ("rtmp_r_find_bridge: for net %d send back router %d.%d\n",
965 NET_VALUE(orig_ddp
->dst_net
), Entry
->NextIRNet
, Entry
->NextIRNode
));
966 if ((status
= ddp_router_output(m
, ifID
, AT_ADDR
, NET_VALUE(orig_ddp
->src_net
),
967 orig_ddp
->src_node
, 0))){
968 dPrintf(D_M_RTMP
, D_L_WARNING
,
969 ("rtmp_r_find_bridge: ddp_router_output failed status=%d\n", status
));
977 * Send the routing table entries in RTMP data packets.
978 * Use split horizon if specified. The Data packets are sent
979 * as full DDP packets, if the last packet is full an empty
980 * packet is sent to tell the recipients that this is the end of
984 static int rtmp_send_table(at_ifaddr_t
*, at_net
, u_char
, short, char, short);
986 static int rtmp_send_table(ifID
, DestNet
, DestNode
, split_hz
, socket
,
988 register at_ifaddr_t
*ifID
; /* interface/port params */
989 register at_net DestNet
; /* net where to send the table */
990 register u_char DestNode
; /* node where to send to table */
991 short split_hz
; /* use split horizon */
992 char socket
; /* the destination socket to send to */
993 short n_neighbors
; /* used to send packets telling we are going down */
1001 register at_ddp_t
*ddp
;
1002 register short EntNb
= 0, sent_tuple
= 0;
1004 if (ifID
->ifRoutingState
< PORT_ONLINE
) {
1005 dPrintf(D_M_RTMP
, D_L_INFO
,
1006 ("rtmp_send_table: port %d activating, we don't send anything!\n",
1011 /* prerare tuples and packets for DDP*/
1012 /* if split horizon, do not send tuples we can reach on the port we
1016 Entry
= &RT_table
[0];
1018 if (!(m
= rtmp_prep_new_packet(ifID
, DestNet
, DestNode
, socket
))) {
1019 dPrintf(D_M_RTMP
, D_L_WARNING
,
1020 ("rtmp_send_table: rtmp_prep_new_packet failed\n"));
1024 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
1025 Buff_ptr
= (char *)((char *)ddp
+ DDP_X_HDR_SIZE
+ 10);
1027 while (EntNb
< RT_maxentry
) {
1029 if (Entry
->NetStop
&& ((Entry
->EntryState
& 0x0F) >= RTE_STATE_SUSPECT
)) {
1030 if (!(split_hz
&& ifID
->ifPort
== Entry
->NetPort
)) {
1033 if (((Entry
->EntryState
& 0x0F) < RTE_STATE_SUSPECT
) || n_neighbors
)
1034 NewDist
= NOTIFY_N_DIST
;
1036 NewDist
= Entry
->NetDist
& 0x1F;
1038 if (Entry
->NetStart
) { /* Extended */
1039 *Buff_ptr
++ = (Entry
->NetStart
& 0xFF00) >> 8;
1040 *Buff_ptr
++ = (Entry
->NetStart
& 0x00FF);
1041 *Buff_ptr
++ = 0x80 | NewDist
;
1042 *Buff_ptr
++ = (Entry
->NetStop
& 0xFF00) >> 8;
1043 *Buff_ptr
++ = (Entry
->NetStop
& 0x00FF);
1044 *Buff_ptr
++ = RTMP_VERSION_NUMBER
;
1047 else { /* non extended tuple */
1048 *Buff_ptr
++ = (Entry
->NetStop
& 0xFF00) >> 8;
1049 *Buff_ptr
++ = (Entry
->NetStop
& 0x00FF);
1050 *Buff_ptr
++ = NewDist
;
1056 if (size
> (DDP_DATA_SIZE
-20)) {
1057 DDPLEN_ASSIGN(ddp
, (size
+ DDP_X_HDR_SIZE
+ 10));
1059 if ((status
= ddp_router_output(m
, ifID
, AT_ADDR
,
1060 NET_VALUE(DestNet
),DestNode
, 0))){
1061 dPrintf(D_M_RTMP
, D_L_WARNING
,
1062 ("rtmp_send_table: ddp_router_output failed status=%d\n",
1066 if ((m
= rtmp_prep_new_packet (ifID
, DestNet
, DestNode
, socket
)) == NULL
){
1067 dPrintf(D_M_RTMP
, D_L_WARNING
,
1068 ("rtmp_send_table: rtmp_prep_new_poacket failed status=%d\n",
1072 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
1073 Buff_ptr
= (char *)((char *)ddp
+ DDP_X_HDR_SIZE
+ 10);
1075 dPrintf(D_M_RTMP_LOW
, D_L_OUTPUT
,
1076 ("rtmp_s_tble: Send %d tuples on port %d\n",
1077 sent_tuple
, ifID
->ifPort
));
1087 * If we have some remaining entries to send, send them now.
1088 * otherwise, the last packet we sent was full, we need to send an empty one
1091 DDPLEN_ASSIGN(ddp
, (size
+ DDP_X_HDR_SIZE
+ 10));
1094 ddp_router_output(m
, ifID
, AT_ADDR
, NET_VALUE(DestNet
),DestNode
, 0))){
1095 dPrintf(D_M_RTMP
, D_L_WARNING
,
1096 ("rtmp_send_table: ddp_router_output failed status=%d\n", status
));
1099 dPrintf(D_M_RTMP_LOW
, D_L_OUTPUT
,
1100 ("rtmp_s_tble: LAST Packet split=%d with %d tuples sent on port %d\n",
1101 split_hz
, sent_tuple
, ifID
->ifPort
));
1107 * rtmp_request: respond to the 3 types of RTMP requests RTMP may receive
1108 * RTMP func =1 : respond with an RTMP Reponse Packet
1109 * RTMP func =2 : respond with the routing table RTMP packet with split horizon
1110 * RTMP func =3 : respond with the routing table RTMP packet no split horizon
1112 * see Inside AppleTalk around page 5-18 for "details"
1115 static void rtmp_request(ifID
, ddp
)
1116 register at_ifaddr_t
*ifID
;
1117 register at_ddp_t
*ddp
;
1120 short split_horizon
= FALSE
;
1124 /* We ignore the request if we're activating on that port */
1126 if (ifID
->ifRoutingState
< PORT_ONLINE
)
1129 /* check RTMP function code */
1131 code
= ddp
->data
[0];
1135 case RTMP_REQ_FUNC1
: /* RTMP Find Bridge */
1137 /* RTMP Request Packet: we send a response with the next IRrange */
1138 dPrintf(D_M_RTMP
, D_L_INPUT
,
1139 ( "rtmp_request: find bridge for net %d port %d node %d.%d\n",
1140 NET_VALUE(ddp
->dst_net
), ifID
->ifPort
,
1141 NET_VALUE(ddp
->src_net
), ddp
->src_node
));
1143 if ((error
= rtmp_r_find_bridge (ifID
, ddp
))) {
1144 dPrintf(D_M_RTMP
, D_L_WARNING
,
1145 ("rtmp_request: Code 1 ddp_r_output failed error=%d\n",
1152 case RTMP_REQ_FUNC2
:
1154 split_horizon
= TRUE
;
1156 case RTMP_REQ_FUNC3
:
1158 /* RTMP Route Request Packet */
1160 dPrintf(D_M_RTMP
, D_L_INPUT
,
1161 ("rtmp_request: received code=%d from %d.%d for %d.%d\n",
1162 code
, NET_VALUE(ddp
->src_net
), ddp
->src_node
,
1163 NET_VALUE(ddp
->dst_net
), ddp
->dst_node
));
1165 rtmp_send_table(ifID
, ddp
->src_net
, ddp
->src_node
,
1166 split_horizon
, ddp
->src_socket
, 0);
1172 /* unknown type of request */
1173 dPrintf(D_M_RTMP
, D_L_WARNING
,
1174 ("rtmp_request : invalid type of request =%d\n",
1181 /* locked version of rtmp_send_port */
1182 void rtmp_send_port_locked(void *arg
)
1184 at_ifaddr_t
*ifID
= (at_ifaddr_t
*)arg
;
1186 rtmp_send_port(ifID
);
1192 * rtmp_send_all_ports : send the routing table on all connected ports
1193 * check for the port status and if ok, send the
1194 * rtmp tuples to the broadcast address for the port
1195 * usually called on timeout every 10 seconds.
1198 void rtmp_send_port(ifID
)
1199 register at_ifaddr_t
*ifID
;
1203 NET_ASSIGN(DestNet
, 0);
1205 if (ifID
&& ifID
->ifRoutingState
== PORT_ONLINE
) {
1206 dPrintf(D_M_RTMP_LOW
, D_L_OUTPUT
,
1207 ("rtmp_send_port: do stuff for port=%d\n",
1209 if (ifID
->ifZipNeedQueries
)
1210 zip_send_queries(ifID
, 0, 0xFF);
1211 if (!ROUTING_MODE
) {
1214 rtmp_send_table(ifID
, DestNet
, 0xFF, 1, RTMP_SOCKET
, 0);
1218 if (ifID
== ifID_home
)
1219 dPrintf(D_M_RTMP_LOW
, D_L_VERBOSE
,
1220 ("I:%5d O:%5d H:%5d dropped:%d\n",
1221 pktsIn
, pktsOut
, pktsHome
, pktsDropped
));
1223 dPrintf(D_M_RTMP_LOW
, D_L_TRACE
,
1224 ("rtmp_send_port: func=0x%x, ifID=0x%x\n",
1225 (u_int
) rtmp_send_port
, (u_int
) ifID
));
1228 timeout (rtmp_send_port_locked
, (caddr_t
)ifID
, 10 * SYS_HZ
);
1232 /* rtmp_dropper: check the number of packet received every x secondes.
1233 * the actual packet dropping is done in ddp_input
1236 void rtmp_dropper(__unused
void *arg
)
1241 pktsIn
= pktsOut
= pktsHome
= pktsDropped
= 0;
1242 timeout(rtmp_dropper
, NULL
, 2*SYS_HZ
);
1248 * rtmp_router_start: perform the sanity checks before declaring the router up
1249 * and running. This function looks for discrepency between the net infos
1250 * for the different ports and seed problems.
1251 * If everything is fine, the state of each port is brought to PORT_ONLINE.\
1252 * ### LD 01/09/95 Changed to correct Zone problem on non seed ports.
1255 int rtmp_router_start(at_kern_err_t
*keP
)
1258 register at_ifaddr_t
*ifID
, *ifID2
;
1259 register short Index
, router_starting_timer
= 0;
1260 register RT_entry
*Entry
;
1261 register at_net_al netStart
, netStop
;
1265 /* clear the static structure used to record routing errors */
1266 bzero(&ke
, sizeof(ke
));
1268 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1270 /* if non seed, need to acquire the right node address */
1272 if ((ifID
->ifFlags
& RTR_SEED_PORT
) == 0) {
1273 if ((ifID
->ifThisCableStart
== 0 && ifID
->ifThisCableEnd
== 0) ||
1274 (ifID
->ifThisCableStart
>= DDP_STARTUP_LOW
&&
1275 ifID
->ifThisCableEnd
<= DDP_STARTUP_HIGH
)) {
1277 if (ifID
->ifThisCableEnd
== 0) {
1278 keP
->error
= KE_NO_SEED
;
1279 keP
->port1
= ifID
->ifPort
;
1280 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1283 keP
->error
= KE_INVAL_RANGE
;
1284 keP
->port1
= ifID
->ifPort
;
1285 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1286 keP
->netr1b
= ifID
->ifThisCableStart
;
1287 keP
->netr1e
= ifID
->ifThisCableEnd
;
1289 ifID
->ifRoutingState
= PORT_ERR_STARTUP
;
1290 RouterError(ifID
->ifPort
, ERTR_CABLE_STARTUP
);
1295 /* we are non seed, so try to acquire the zones for that guy */
1296 ifID
->ifZipNeedQueries
= 1;
1298 dPrintf(D_M_RTMP
, D_L_STARTUP
,
1299 ("rtmp_router_start: call elap_online for Non Seed port #%d cable =%d-%d\n",
1300 ifID
->ifPort
, CableStart
, CableStop
));
1301 if ((err
= elap_online3(ifID
)))
1306 /* Check if we have a problem with the routing table size */
1308 if (ErrorRTMPoverflow
) {
1309 keP
->error
= KE_RTMP_OVERFLOW
;
1314 /* Now, check that we don't have a conflict in between our interfaces */
1315 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1317 /* check if the RoutingState != PORT_ONERROR */
1318 if (ifID
->ifRoutingState
< PORT_ACTIVATING
) {
1322 if ((ifID
->ifThisCableStart
== 0 && ifID
->ifThisCableEnd
== 0) ||
1323 (ifID
->ifThisCableStart
>= DDP_STARTUP_LOW
&&
1324 ifID
->ifThisCableEnd
<= DDP_STARTUP_HIGH
)) {
1326 if (ifID
->ifThisCableEnd
== 0) {
1327 keP
->error
= KE_NO_SEED
;
1328 keP
->port1
= ifID
->ifPort
;
1329 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1332 keP
->error
= KE_INVAL_RANGE
;
1333 keP
->port1
= ifID
->ifPort
;
1334 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1335 keP
->netr1b
= ifID
->ifThisCableStart
;
1336 keP
->netr1e
= ifID
->ifThisCableEnd
;
1339 ifID
->ifRoutingState
= PORT_ERR_STARTUP
;
1340 RouterError(ifID
->ifPort
, ERTR_CABLE_STARTUP
);
1345 /* check the interface address against all other ifs */
1347 netStart
= ifID
->ifThisCableStart
;
1348 netStop
= ifID
->ifThisCableEnd
;
1350 for (ifID2
= TAILQ_NEXT(ifID
, aa_link
); ifID2
;
1351 ifID2
= TAILQ_NEXT(ifID2
, aa_link
)) {
1353 if (((netStart
>= ifID2
->ifThisCableStart
) &&
1354 (netStart
<= ifID2
->ifThisCableEnd
)) ||
1355 ((netStop
>= ifID2
->ifThisCableStart
) &&
1356 (netStop
<= ifID2
->ifThisCableEnd
)) ||
1357 ((ifID2
->ifThisCableStart
>= netStart
) &&
1358 (ifID2
->ifThisCableStart
<= netStop
)) ||
1359 ((ifID2
->ifThisCableEnd
>= netStart
) &&
1360 (ifID2
->ifThisCableEnd
<= netStop
)) ) {
1362 keP
->error
= KE_CONF_RANGE
;
1363 keP
->port1
= ifID
->ifPort
;
1364 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1365 keP
->port2
= ifID2
->ifPort
;
1366 strlcpy(keP
->name2
, ifID2
->ifName
,sizeof(keP
->name2
));
1367 keP
->netr1b
= ifID
->ifThisCableStart
;
1368 keP
->netr1e
= ifID
->ifThisCableEnd
;
1369 ifID
->ifRoutingState
= PORT_ERR_CABLER
;
1370 RouterError(ifID
->ifPort
, ERTR_CABLE_CONFLICT
);
1376 /* ### LD 01/04/94: We need to fill in the next IR info in the routing table */
1377 Entry
= rt_blookup(ifID
->ifThisCableEnd
);
1379 if (Entry
== NULL
) {
1380 dPrintf(D_M_RTMP
, D_L_ERROR
,
1381 ("rtmp_router_start: we don't know our cable range port=%d\n",
1388 * Note: At this point, non seed ports may not be aware of their Default zone
1391 if (!(ifID
->ifFlags
& RTR_SEED_PORT
)) {
1392 ifID
->ifDefZone
= 0;
1393 Entry
->EntryState
|= (RTE_STATE_GOOD
|RTE_STATE_UPDATED
);
1396 ifID
->ifRoutingState
= PORT_ONLINE
;
1397 ifID
->ifState
= LAP_ONLINE
;
1399 /* set the right net and node for each port */
1400 Entry
->NextIRNet
= ifID
->ifThisNode
.s_net
;
1401 Entry
->NextIRNode
= ifID
->ifThisNode
.s_node
;
1403 dPrintf(D_M_RTMP
, D_L_STARTUP
,
1404 ("rtmp_router_start: bring port=%d [%d.%d]... on line\n",
1405 ifID
->ifPort
, ifID
->ifThisNode
.s_net
,
1406 ifID
->ifThisNode
.s_node
));
1411 * Everything is fine, we can begin to babble on the net...
1414 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1415 if (ifID
->ifRoutingState
== PORT_ONLINE
) {
1416 rtmp_send_port(ifID
);
1417 timeout(rtmp_timeout
, (caddr_t
)ifID
, (50+ifID
->ifPort
) * SYS_HZ
);
1418 if (ifID
->ifRoutingState
< PORT_ACTIVATING
) {
1424 /* Check if we have a problem with the routing or zip table size */
1426 if (ErrorRTMPoverflow
) {
1427 keP
->error
= KE_RTMP_OVERFLOW
;
1430 if (ErrorZIPoverflow
) {
1431 keP
->error
= KE_ZIP_OVERFLOW
;
1435 /* sleep for 11 seconds */
1439 /* *** eventually this will be the ifID for the interface
1440 being brought up in router mode *** */
1441 /* *** router sends rtmp packets every 10 seconds *** */
1442 msleep(&ifID_home
->startup_inprogress
, atalk_mutex
,
1443 PSOCK
| PCATCH
, "router_start1", &ts
))
1448 /* Is the stack still up ? */
1449 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
) {
1456 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1458 if (ifID
->ifRoutingState
< PORT_ACTIVATING
) {
1462 if ((ifID
->ifZipNeedQueries
)
1463 && (ifID
->ifFlags
& RTR_SEED_PORT
) == 0) {
1464 dPrintf(D_M_RTMP
, D_L_STARTUP
,
1465 ("rtmp_router_start: send Zip Queries for Port %d\n",
1467 zip_send_queries(ifID
, 0, 0xFF);
1469 if (router_starting_timer
>= 10) {
1470 dPrintf(D_M_RTMP
, D_L_WARNING
,
1471 ("rtmp_router_start: no received response to ZipNeedQueries\n"));
1472 keP
->error
= KE_NO_ZONES_FOUND
;
1473 keP
->port1
= ifID
->ifPort
;
1474 strlcpy(keP
->name1
, ifID
->ifName
,sizeof(keP
->name1
));
1475 keP
->netr1b
= ifID
->ifThisCableStart
;
1476 keP
->netr1e
= ifID
->ifThisCableEnd
;
1477 ifID
->ifRoutingState
= PORT_ERR_CABLER
;
1478 RouterError(ifID
->ifPort
, ERTR_CABLE_CONFLICT
);
1482 dPrintf(D_M_RTMP
, D_L_STARTUP
,
1483 ("rtmp_router_start: waiting for zone info to complete\n"));
1484 /* sleep for 10 seconds */
1488 /* *** eventually this will be the ifID for the
1489 interface being brought up in router mode *** */
1490 msleep(&ifID_home
->startup_inprogress
, atalk_mutex
,
1491 PSOCK
| PCATCH
, "router_start2", &ts
))
1496 /* Is the stack still up ? */
1497 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
) {
1503 router_starting_timer
++;
1509 /* At This Point, check if we know the default zones for non seed port */
1511 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1513 if (ifID
->ifRoutingState
< PORT_ACTIVATING
)
1516 if (!(ifID
->ifFlags
& RTR_SEED_PORT
)) {
1517 Entry
= rt_blookup(ifID
->ifThisCableEnd
);
1519 if (Entry
== NULL
) {
1520 dPrintf(D_M_RTMP
, D_L_ERROR
,
1521 ("rtmp_router_start: (2)we don't know our cable range port=%d\n",
1526 dPrintf(D_M_RTMP
, D_L_STARTUP
,
1527 ("rtmp_router_start: if %s set to permanent\n",
1529 Entry
->NetDist
= 0; /* added 4-29-96 jjs, prevent direct
1530 nets from showing non-zero
1532 /* upgrade the non seed ports. */
1533 Entry
->EntryState
|= RTE_STATE_PERMANENT
;
1535 Index
= zt_ent_zindex(Entry
->ZoneBitMap
);
1537 dPrintf(D_M_RTMP
, D_L_ERROR
,
1538 ("rtmp_router_start: still don't know default zone for port %d\n",
1541 ifID
->ifDefZone
= Index
;
1542 if ((ifID
== ifID_home
) || MULTIHOME_MODE
) {
1543 ifID
->ifZoneName
= ZT_table
[Index
-1].Zone
;
1544 (void)regDefaultZone(ifID
);
1546 /* Send zone change event */
1547 atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ZONEUPDATED
, 0, &(ifID
->ifZoneName
));
1553 /* Check if we have a problem with the routing or zip table size */
1555 if (ErrorRTMPoverflow
) {
1556 keP
->error
= KE_RTMP_OVERFLOW
;
1559 if (ErrorZIPoverflow
) {
1560 keP
->error
= KE_ZIP_OVERFLOW
;
1565 * Handle the Home Port specifics
1568 /* set the router address as being us no matter what*/
1569 ifID_home
->ifARouter
= ifID_home
->ifThisNode
;
1570 ifID_home
->ifRouterState
= ROUTER_UPDATED
;
1572 /* prepare the packet dropper timer */
1573 timeout (rtmp_dropper
, NULL
, 1*SYS_HZ
);
1578 dPrintf(D_M_RTMP
,D_L_ERROR
,
1579 ("rtmp_router_start: error type=%d occurred on port %d\n",
1580 ifID
->ifRoutingState
, ifID
->ifPort
));
1582 /* if there's no keP->error, copy the local ke structure,
1583 since the error occurred asyncronously */
1584 if ((!keP
->error
) && ke
.error
)
1585 bcopy(&ke
, keP
, sizeof(ke
));
1588 /* to return the error in keP, the ioctl has to return 0 */
1590 return((keP
->error
)? 0: err
);
1591 } /* rtmp_router_start */
1593 void rtmp_router_start_tmo(void *arg
)
1595 (void)rtmp_router_start_tmo((at_kern_err_t
*)arg
);
1598 void rtmp_shutdown(void)
1600 register at_ifaddr_t
*ifID
;
1603 NET_ASSIGN(DestNet
, 0);
1605 dPrintf(D_M_RTMP
, D_L_SHUTDN
,
1606 ("rtmp_shutdown:stop sending to all ports\n"));
1608 untimeout(rtmp_dropper
, (void *)0);
1609 untimeout(rtmp_router_start_tmo
, (void *)1); /* added for 2225395 */
1610 untimeout(rtmp_router_start_tmo
, (void *)3); /* added for 2225395 */
1612 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
1613 if (ifID
->ifRoutingState
> PORT_OFFLINE
) {
1614 if (ifID
->ifRoutingState
== PORT_ONLINE
) {
1615 untimeout(rtmp_send_port_locked
, (caddr_t
)ifID
);
1616 untimeout(rtmp_timeout
, (caddr_t
) ifID
);
1619 * it's better to notify the neighbour routers that we are going down
1622 rtmp_send_table(ifID
, DestNet
, 0xFF, TRUE
,
1625 ifID
->ifRoutingState
= PORT_OFFLINE
;
1627 dPrintf(D_M_RTMP
, D_L_SHUTDN
,
1628 ("rtmp_shutdown: routing on port=%d... off line\nStats:\n",
1630 dPrintf(D_M_RTMP
, D_L_SHUTDN
,
1631 ("fwdBytes : %ld\nfwdPackets : %ld\ndroppedBytes : %ld\ndroppedPkts : %ld\n",
1632 ifID
->ifStatistics
.fwdBytes
, ifID
->ifStatistics
.fwdPkts
,
1633 ifID
->ifStatistics
.droppedBytes
, ifID
->ifStatistics
.droppedPkts
));
1641 * Remove all entries associated with the specified port.
1643 void rtmp_purge(ifID
)
1648 RT_entry
*en
= &RT_table
[0];
1650 for (i
=0; i
< RT_maxentry
; i
++) {
1651 state
= en
->EntryState
& 0x0F;
1652 if ((state
> RTE_STATE_UNUSED
) && (state
!= RTE_STATE_PERMANENT
)
1653 && en
->NetStop
&& en
->NetDist
&& (en
->NetPort
== ifID
->ifPort
)) {
1654 zt_remove_zones(en
->ZoneBitMap
);
1655 RT_DELETE(en
->NetStop
, en
->NetStart
);