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