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