]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/ddp_r_rtmp.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / netat / ddp_r_rtmp.c
1 /*
2 * Copyright (c) 1994, 1996-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*--------------------------------------------------------------------------
29 * Router RTMP protocol functions:
30 *
31 * This file contains Routing specifics to handle RTMP packets and
32 * the maintenance of the routing table through....
33 *
34 * The entry point for the rtmp input in ddp is valid only when we're
35 * running in router mode.
36 *
37 *
38 * 0.01 03/22/94 Laurent Dumont Creation
39 * Modified for MP, 1996 by Tuyen Nguyen
40 * Added AURP support, April 8, 1996 by Tuyen Nguyen
41 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
42 *
43 *-------------------------------------------------------------------------
44 */
45
46 #include <sys/errno.h>
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <machine/spl.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/proc.h>
53 #include <sys/filedesc.h>
54 #include <sys/fcntl.h>
55 #include <sys/mbuf.h>
56 #include <sys/ioctl.h>
57 #include <sys/malloc.h>
58 #include <kern/locks.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61
62 #include <net/if.h>
63
64 #include <netat/sysglue.h>
65 #include <netat/appletalk.h>
66 #include <netat/at_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>
74
75 #include <sys/kern_event.h>
76
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;
81
82
83 int rtmp_router_start(at_kern_err_t *);
84 void rtmp_router_start_tmo(void *);
85
86
87
88 static at_kern_err_t ke;
89 /* Used to record error discovered in rtmp_update() */
90
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 *);
98
99 extern short ErrorRTMPoverflow, ErrorZIPoverflow;
100 extern lck_mtx_t * atalk_mutex;
101
102 extern int pktsIn, pktsOut, pktsDropped, pktsHome;
103
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
112 void 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
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;
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 register u_char SenderNodeID = rtmp->at_rtmp_id[0];
263 char *TuplePtr;
264 short state;
265
266 bzero(&NewRoute, sizeof(RT_entry));
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 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);
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 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);
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 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);
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 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);
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
687 #ifdef AURP_SUPPORT
688 if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
689 ddp_AURPsendx(AURPCODE_RTUPDATE,
690 (void *)&NewRoute, AURPEV_NetDistChange);
691 #endif
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;
712 #ifdef AURP_SUPPORT
713 else if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
714 ddp_AURPsendx(AURPCODE_RTUPDATE,
715 (void *)&NewRoute, AURPEV_NetAdded);
716 #endif
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
747 void rtmp_timeout(void *arg)
748 {
749 at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
750 register u_char state;
751 short i;
752 RT_entry *en = &RT_table[0];
753
754 atalk_lock();
755
756 if (ifID->ifRoutingState < PORT_ONLINE) {
757 atalk_unlock();
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
766 for (i = 0 ; i < RT_maxentry; i++,en++) {
767
768 /* we want to age "learned" nets, not directly connected ones */
769 state = en->EntryState & 0x0F;
770
771
772 if (state > RTE_STATE_UNUSED &&
773 !(en->EntryState & RTE_STATE_PERMANENT) && en->NetStop &&
774 en->NetDist && en->NetPort == ifID->ifPort) {
775
776 /* if entry has been updated recently, just clear the UPDATED
777 bit. if bit not set, then we can age the entry */
778 if (en->EntryState & RTE_STATE_UPDATED) {
779 en->EntryState &= ~RTE_STATE_UPDATED;
780 continue;
781 }
782 else
783 state = state >> 1 ; /* decrement state */
784
785 if (state == RTE_STATE_UNUSED) {/* was BAD, needs to delete */
786 dPrintf(D_M_RTMP, D_L_INFO,
787 ("rtmp_timeout: Bad State for %d-%d (e#%d): remove\n",
788 en->NetStart, en->NetStop, i));
789 #ifdef AURP_SUPPORT
790 if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP))
791 ddp_AURPsendx(AURPCODE_RTUPDATE,
792 (void *)en, AURPEV_NetDeleted);
793 #endif
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 }
809 timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ);
810
811 atalk_unlock();
812 }
813
814 /*
815 * rtmp_prep_new_packet: allocate a ddp packet for RTMP use (reply to a RTMP request or
816 * Route Data Request, or generation of RTMP data packets.
817 * The ddp header is filled with relevant information, as well as
818 * the beginning of the rtmp packet with the following info:
819 * Router's net number (2bytes)
820 * ID Length = 8 (1byte)
821 * Router's node ID (1byte)
822 * Extended Range Start (2bytes)
823 * Range + dist (0x80) (1byte)
824 * Extended Range End (2bytes)
825 * Rtmp version (0x82) (1byte)
826 *
827 */
828
829 gbuf_t *rtmp_prep_new_packet (at_ifaddr_t *, at_net, u_char, char);
830
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;
836
837 {
838 gbuf_t *m;
839 register at_ddp_t *ddp;
840 register char * rtmp_data;
841
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);
845 }
846
847 gbuf_rinc(m,AT_WR_OFFSET);
848 gbuf_wset(m,DDP_X_HDR_SIZE + 10);
849 ddp = (at_ddp_t *)(gbuf_rptr(m));
850
851 /*
852 * Prepare the DDP header of the new packet
853 */
854
855
856 ddp->unused = ddp->hopcount = 0;
857
858 UAS_ASSIGN(ddp->checksum, 0);
859
860 NET_NET(ddp->dst_net, DstNet);
861 ddp->dst_node = DstNode;
862 ddp->dst_socket = socket;
863
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;
868
869 /*
870 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
871 * (this works only if we are on an extended net)
872 */
873
874 rtmp_data = ddp->data;
875
876 *rtmp_data++ = (ifID->ifThisNode.s_net & 0xff00) >> 8;
877 *rtmp_data++ = ifID->ifThisNode.s_net & 0x00ff ;
878 *rtmp_data++ = 8;
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;
886
887 return (m);
888
889
890 }
891 int rtmp_r_find_bridge(at_ifaddr_t *, at_ddp_t *);
892
893 int rtmp_r_find_bridge(ifID, orig_ddp)
894 register at_ifaddr_t *ifID;
895 register at_ddp_t *orig_ddp;
896
897 {
898 gbuf_t *m;
899 register int size, status;
900 register at_ddp_t *ddp;
901 register char * rtmp_data;
902 RT_entry *Entry;
903
904
905 /* find the bridge for the querried net */
906
907 Entry = rt_blookup(NET_VALUE(orig_ddp->dst_net));
908
909 if (Entry == NULL) {
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)));
912 return (1);
913 }
914
915
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"));
920 return (ENOBUFS);
921 }
922
923 gbuf_rinc(m,AT_WR_OFFSET);
924 gbuf_wset(m,size);
925 ddp = (at_ddp_t *)(gbuf_rptr(m));
926
927 /*
928 * Prepare the DDP header of the new packet
929 */
930
931 ddp->unused = ddp->hopcount = 0;
932
933 DDPLEN_ASSIGN(ddp, size);
934 UAS_ASSIGN(ddp->checksum, 0);
935
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;
939
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;
944
945 /*
946 * Prepare the RTMP header (Router Net, ID, Node and Net Tuple
947 * (this works only if we are on an extended net)
948 */
949
950 rtmp_data = ddp->data;
951
952 *rtmp_data++ = (Entry->NextIRNet & 0xff00) >> 8;
953 *rtmp_data++ = Entry->NextIRNet & 0x00ff ;
954 *rtmp_data++ = 8;
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;
962
963
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));
970 return (status);
971 }
972 return (0);
973 }
974
975 /*
976 * rtmp_send_table:
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
981 * the table...
982 *
983 */
984 static int rtmp_send_table(at_ifaddr_t *, at_net, u_char, short, char, short);
985
986 static int rtmp_send_table(ifID, DestNet, DestNode, split_hz, socket,
987 n_neighbors)
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 */
994 {
995
996 RT_entry *Entry;
997 char *Buff_ptr;
998 u_char NewDist;
999 gbuf_t *m;
1000 short size,status ;
1001 register at_ddp_t *ddp;
1002 register short EntNb = 0, sent_tuple = 0;
1003
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",
1007 ifID->ifPort));
1008 return (0);
1009 }
1010
1011 /* prerare tuples and packets for DDP*/
1012 /* if split horizon, do not send tuples we can reach on the port we
1013 * want to send too
1014 */
1015
1016 Entry = &RT_table[0];
1017 size = 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"));
1021 return(ENOBUFS);
1022 }
1023
1024 ddp = (at_ddp_t *)(gbuf_rptr(m));
1025 Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10);
1026
1027 while (EntNb < RT_maxentry) {
1028
1029 if (Entry->NetStop && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT)) {
1030 if (!(split_hz && ifID->ifPort == Entry->NetPort)) {
1031 sent_tuple++;
1032
1033 if (((Entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) || n_neighbors)
1034 NewDist = NOTIFY_N_DIST;
1035 else
1036 NewDist = Entry->NetDist & 0x1F;
1037
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;
1045 size += 6;
1046 }
1047 else { /* non extended tuple */
1048 *Buff_ptr++ = (Entry->NetStop & 0xFF00) >> 8;
1049 *Buff_ptr++ = (Entry->NetStop & 0x00FF);
1050 *Buff_ptr++ = NewDist;
1051 size += 3;
1052 }
1053 }
1054 }
1055
1056 if (size > (DDP_DATA_SIZE-20)) {
1057 DDPLEN_ASSIGN(ddp, (size + DDP_X_HDR_SIZE + 10));
1058 gbuf_winc(m,size);
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",
1063 status));
1064 return (status);
1065 }
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",
1069 status));
1070 return (ENOBUFS);
1071 }
1072 ddp = (at_ddp_t *)(gbuf_rptr(m));
1073 Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10);
1074
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));
1078 sent_tuple = 0;
1079 size = 0;
1080 }
1081
1082 Entry++;
1083 EntNb++;
1084 }
1085
1086 /*
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
1089 */
1090
1091 DDPLEN_ASSIGN(ddp, (size + DDP_X_HDR_SIZE + 10));
1092 gbuf_winc(m,size);
1093 if ((status =
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));
1097 return (status);
1098 }
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));
1102
1103 return (0);
1104 }
1105
1106 /*
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
1111 *
1112 * see Inside AppleTalk around page 5-18 for "details"
1113 */
1114
1115 static void rtmp_request(ifID, ddp)
1116 register at_ifaddr_t *ifID;
1117 register at_ddp_t *ddp;
1118 {
1119
1120 short split_horizon = FALSE;
1121 short code;
1122 short error;
1123
1124 /* We ignore the request if we're activating on that port */
1125
1126 if (ifID->ifRoutingState < PORT_ONLINE)
1127 return;
1128
1129 /* check RTMP function code */
1130
1131 code = ddp->data[0];
1132
1133 switch (code) {
1134
1135 case RTMP_REQ_FUNC1: /* RTMP Find Bridge */
1136
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));
1142
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",
1146 error));
1147 return;
1148 }
1149
1150 break;
1151
1152 case RTMP_REQ_FUNC2:
1153
1154 split_horizon = TRUE;
1155
1156 case RTMP_REQ_FUNC3:
1157
1158 /* RTMP Route Request Packet */
1159
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));
1164
1165 rtmp_send_table(ifID, ddp->src_net, ddp->src_node,
1166 split_horizon, ddp->src_socket, 0);
1167
1168 break;
1169
1170 default:
1171
1172 /* unknown type of request */
1173 dPrintf(D_M_RTMP, D_L_WARNING,
1174 ("rtmp_request : invalid type of request =%d\n",
1175 code));
1176 break;
1177 }
1178
1179 }
1180
1181 /* locked version of rtmp_send_port */
1182 void rtmp_send_port_locked(void *arg)
1183 {
1184 at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
1185 atalk_lock();
1186 rtmp_send_port(ifID);
1187 atalk_unlock();
1188 }
1189
1190
1191 /*
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.
1196 */
1197
1198 void rtmp_send_port(ifID)
1199 register at_ifaddr_t *ifID;
1200 {
1201 at_net DestNet;
1202
1203 NET_ASSIGN(DestNet, 0);
1204
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",
1208 ifID->ifPort));
1209 if (ifID->ifZipNeedQueries)
1210 zip_send_queries(ifID, 0, 0xFF);
1211 if (!ROUTING_MODE) {
1212 return;
1213 }
1214 rtmp_send_table(ifID, DestNet, 0xFF, 1, RTMP_SOCKET, 0);
1215 }
1216
1217 #if DEBUG
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));
1222
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));
1226 #endif
1227
1228 timeout (rtmp_send_port_locked, (caddr_t)ifID, 10 * SYS_HZ);
1229
1230 }
1231
1232 /* rtmp_dropper: check the number of packet received every x secondes.
1233 * the actual packet dropping is done in ddp_input
1234 */
1235
1236 void rtmp_dropper(__unused void *arg)
1237 {
1238
1239 atalk_lock();
1240
1241 pktsIn = pktsOut = pktsHome = pktsDropped = 0;
1242 timeout(rtmp_dropper, NULL, 2*SYS_HZ);
1243
1244 atalk_unlock();
1245 }
1246
1247 /*
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.
1253 */
1254
1255 int rtmp_router_start(at_kern_err_t *keP)
1256 {
1257 int err = 0;
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;
1262 struct timespec ts;
1263
1264
1265 /* clear the static structure used to record routing errors */
1266 bzero(&ke, sizeof(ke));
1267
1268 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1269
1270 /* if non seed, need to acquire the right node address */
1271
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)) {
1276
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));
1281 }
1282 else {
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;
1288 }
1289 ifID->ifRoutingState = PORT_ERR_STARTUP;
1290 RouterError(ifID->ifPort, ERTR_CABLE_STARTUP);
1291
1292 goto error;
1293 }
1294
1295 /* we are non seed, so try to acquire the zones for that guy */
1296 ifID->ifZipNeedQueries = 1;
1297
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)))
1302 goto error;
1303 }
1304 }
1305
1306 /* Check if we have a problem with the routing table size */
1307
1308 if (ErrorRTMPoverflow) {
1309 keP->error = KE_RTMP_OVERFLOW;
1310 goto error;
1311 }
1312
1313
1314 /* Now, check that we don't have a conflict in between our interfaces */
1315 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1316
1317 /* check if the RoutingState != PORT_ONERROR */
1318 if (ifID->ifRoutingState < PORT_ACTIVATING) {
1319 goto error;
1320 }
1321
1322 if ((ifID->ifThisCableStart == 0 && ifID->ifThisCableEnd == 0) ||
1323 (ifID->ifThisCableStart >= DDP_STARTUP_LOW &&
1324 ifID->ifThisCableEnd <= DDP_STARTUP_HIGH)) {
1325
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));
1330 }
1331 else {
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;
1337 }
1338
1339 ifID->ifRoutingState = PORT_ERR_STARTUP;
1340 RouterError(ifID->ifPort, ERTR_CABLE_STARTUP);
1341
1342 goto error;
1343 }
1344
1345 /* check the interface address against all other ifs */
1346
1347 netStart = ifID->ifThisCableStart;
1348 netStop = ifID->ifThisCableEnd;
1349
1350 for (ifID2 = TAILQ_NEXT(ifID, aa_link); ifID2;
1351 ifID2 = TAILQ_NEXT(ifID2, aa_link)) {
1352
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)) ) {
1361
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);
1371 goto error;
1372 }
1373
1374 }
1375
1376 /* ### LD 01/04/94: We need to fill in the next IR info in the routing table */
1377 Entry = rt_blookup(ifID->ifThisCableEnd);
1378
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",
1382 ifID->ifPort));
1383
1384 goto error;
1385 }
1386
1387 /*
1388 * Note: At this point, non seed ports may not be aware of their Default zone
1389 */
1390
1391 if (!(ifID->ifFlags & RTR_SEED_PORT)) {
1392 ifID->ifDefZone = 0;
1393 Entry->EntryState |= (RTE_STATE_GOOD|RTE_STATE_UPDATED);
1394 }
1395
1396 ifID->ifRoutingState = PORT_ONLINE;
1397 ifID->ifState = LAP_ONLINE;
1398
1399 /* set the right net and node for each port */
1400 Entry->NextIRNet = ifID->ifThisNode.s_net;
1401 Entry->NextIRNode= ifID->ifThisNode.s_node;
1402
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));
1407
1408 }
1409
1410 /*
1411 * Everything is fine, we can begin to babble on the net...
1412 */
1413
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) {
1419 goto error;
1420 }
1421 }
1422 }
1423
1424 /* Check if we have a problem with the routing or zip table size */
1425
1426 if (ErrorRTMPoverflow) {
1427 keP->error = KE_RTMP_OVERFLOW;
1428 goto error;
1429 }
1430 if (ErrorZIPoverflow) {
1431 keP->error = KE_ZIP_OVERFLOW;
1432 goto error;
1433 }
1434
1435 /* sleep for 11 seconds */
1436 ts.tv_sec = 11;
1437 ts.tv_nsec = 0;
1438 if ((err =
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))
1444 != EWOULDBLOCK) {
1445 goto error;
1446 }
1447
1448 /* Is the stack still up ? */
1449 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) {
1450 err = ECONNABORTED;
1451 goto error;
1452 }
1453
1454 startZoneInfo:
1455 err = 0;
1456 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1457
1458 if (ifID->ifRoutingState < PORT_ACTIVATING) {
1459 goto error;
1460 }
1461
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",
1466 ifID->ifPort));
1467 zip_send_queries(ifID, 0, 0xFF);
1468
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);
1479 goto error;
1480 }
1481
1482 dPrintf(D_M_RTMP, D_L_STARTUP,
1483 ("rtmp_router_start: waiting for zone info to complete\n"));
1484 /* sleep for 10 seconds */
1485 ts.tv_sec = 10;
1486 ts.tv_nsec = 0;
1487 if ((err =
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))
1492 != EWOULDBLOCK) {
1493 goto error;
1494 }
1495
1496 /* Is the stack still up ? */
1497 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) {
1498 err = ECONNABORTED;
1499 goto error;
1500 }
1501
1502 err = 0;
1503 router_starting_timer++;
1504 goto startZoneInfo;
1505 }
1506
1507 }
1508
1509 /* At This Point, check if we know the default zones for non seed port */
1510
1511 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1512
1513 if (ifID->ifRoutingState < PORT_ACTIVATING)
1514 goto error;
1515
1516 if (!(ifID->ifFlags & RTR_SEED_PORT)) {
1517 Entry = rt_blookup(ifID->ifThisCableEnd);
1518
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",
1522 ifID->ifPort));
1523 goto error;
1524 }
1525
1526 dPrintf(D_M_RTMP, D_L_STARTUP,
1527 ("rtmp_router_start: if %s set to permanent\n",
1528 ifID->ifName));
1529 Entry->NetDist = 0; /* added 4-29-96 jjs, prevent direct
1530 nets from showing non-zero
1531 distance */
1532 /* upgrade the non seed ports. */
1533 Entry->EntryState |= RTE_STATE_PERMANENT;
1534
1535 Index = zt_ent_zindex(Entry->ZoneBitMap);
1536 if (Index <= 0) {
1537 dPrintf(D_M_RTMP, D_L_ERROR,
1538 ("rtmp_router_start: still don't know default zone for port %d\n",
1539 ifID->ifPort));
1540 } else {
1541 ifID->ifDefZone = Index;
1542 if ((ifID == ifID_home) || MULTIHOME_MODE) {
1543 ifID->ifZoneName = ZT_table[Index-1].Zone;
1544 (void)regDefaultZone(ifID);
1545
1546 /* Send zone change event */
1547 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
1548 }
1549 }
1550 }
1551 }
1552
1553 /* Check if we have a problem with the routing or zip table size */
1554
1555 if (ErrorRTMPoverflow) {
1556 keP->error = KE_RTMP_OVERFLOW;
1557 goto error;
1558 }
1559 if (ErrorZIPoverflow) {
1560 keP->error = KE_ZIP_OVERFLOW;
1561 goto error;
1562 }
1563
1564 /*
1565 * Handle the Home Port specifics
1566 */
1567
1568 /* set the router address as being us no matter what*/
1569 ifID_home->ifARouter = ifID_home->ifThisNode;
1570 ifID_home->ifRouterState = ROUTER_UPDATED;
1571
1572 /* prepare the packet dropper timer */
1573 timeout (rtmp_dropper, NULL, 1*SYS_HZ);
1574
1575 return(0);
1576
1577 error:
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));
1581
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));
1586 rtmp_shutdown();
1587
1588 /* to return the error in keP, the ioctl has to return 0 */
1589
1590 return((keP->error)? 0: err);
1591 } /* rtmp_router_start */
1592
1593 void rtmp_router_start_tmo(void *arg)
1594 {
1595 (void)rtmp_router_start_tmo((at_kern_err_t*)arg);
1596 }
1597
1598 void rtmp_shutdown(void)
1599 {
1600 register at_ifaddr_t *ifID;
1601 at_net DestNet;
1602
1603 NET_ASSIGN(DestNet, 0);
1604
1605 dPrintf(D_M_RTMP, D_L_SHUTDN,
1606 ("rtmp_shutdown:stop sending to all ports\n"));
1607
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 */
1611
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);
1617 }
1618 /*
1619 * it's better to notify the neighbour routers that we are going down
1620 */
1621 if (ROUTING_MODE)
1622 rtmp_send_table(ifID, DestNet, 0xFF, TRUE,
1623 RTMP_SOCKET, TRUE);
1624
1625 ifID->ifRoutingState = PORT_OFFLINE;
1626
1627 dPrintf(D_M_RTMP, D_L_SHUTDN,
1628 ("rtmp_shutdown: routing on port=%d... off line\nStats:\n",
1629 ifID->ifPort));
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));
1634
1635 }
1636 }
1637
1638 }
1639
1640 /*
1641 * Remove all entries associated with the specified port.
1642 */
1643 void rtmp_purge(ifID)
1644 at_ifaddr_t *ifID;
1645 {
1646 u_char state;
1647 int i;
1648 RT_entry *en = &RT_table[0];
1649
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);
1656 }
1657 en++;
1658 }
1659 }