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