1/* 2 * $Id: rtmp.c,v 1.17 2009-12-08 03:21:16 didg Exp $ 3 * 4 * Copyright (c) 1990,1993 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <stdlib.h> 13#include <string.h> 14#include <errno.h> 15#include <atalk/logger.h> 16#include <sys/types.h> 17#include <sys/param.h> 18#include <sys/socket.h> 19#include <sys/ioctl.h> 20#ifdef TRU64 21#include <sys/mbuf.h> 22#include <net/route.h> 23#endif /* TRU64 */ 24#include <net/if.h> 25#include <net/route.h> 26#include <netatalk/endian.h> 27#include <netatalk/at.h> 28 29#ifdef __svr4__ 30#include <sys/sockio.h> 31#endif /* __svr4__ */ 32 33#include <atalk/ddp.h> 34#include <atalk/atp.h> 35#include <atalk/rtmp.h> 36 37#include "interface.h" 38#include "gate.h" 39#include "rtmp.h" 40#include "zip.h" 41#include "list.h" 42#include "atserv.h" 43#include "route.h" 44#include "main.h" 45 46void rtmp_delzonemap(struct rtmptab *rtmp) 47{ 48 struct list *lz, *flz, *lr, *flr; 49 struct ziptab *zt; 50 51 lz = rtmp->rt_zt; 52 while ( lz ) { /* for each zone */ 53 zt = (struct ziptab *)lz->l_data; 54 lr = zt->zt_rt; 55 while ( lr ) { /* for each route */ 56 if ( (struct rtmptab *)lr->l_data == rtmp ) { 57 if ( lr->l_prev == NULL ) { /* head */ 58 if ( lr->l_next == NULL ) { /* last route in zone */ 59 if ( zt->zt_prev == NULL ) { 60 ziptab = zt->zt_next; 61 } else { 62 zt->zt_prev->zt_next = zt->zt_next; 63 } 64 if ( zt->zt_next == NULL ) { 65 ziplast = zt->zt_prev; 66 } else { 67 zt->zt_next->zt_prev = zt->zt_prev; 68 } 69 free( zt->zt_bcast ); 70 free( zt->zt_name ); 71 free( zt ); 72 } else { 73 zt->zt_rt = lr->l_next; 74 } 75 } else { 76 lr->l_prev->l_next = lr->l_next; 77 } 78 if ( lr->l_next != NULL ) { 79 lr->l_next->l_prev = lr->l_prev; 80 } 81 flr = lr; 82 lr = lr->l_next; 83 free( flr ); 84 } else { 85 lr = lr->l_next; 86 } 87 } 88 flz = lz; 89 lz = lz->l_next; 90 free( flz ); 91 } 92 rtmp->rt_zt = NULL; 93} 94 95 96/* 97 * Complete configuration for phase 1 interface using RTMP information. 98 */ 99static int rtmp_config( struct rtmp_head *rh, struct interface *iface) 100{ 101 extern int stabletimer; 102 int cc; 103 104 /* 105 * If we're configuring a phase 2 interface, don't complete 106 * configuration with RTMP. 107 */ 108 if ( iface->i_flags & IFACE_PHASE2 ) { 109 LOG(log_info, logtype_atalkd, "rtmp_config ignoring data" ); 110 return 0; 111 } 112 113 /* 114 * Check our seed information, and reconfigure. 115 */ 116 if ( rh->rh_net != iface->i_addr.sat_addr.s_net ) { 117 if (( iface->i_flags & IFACE_SEED ) && 118 rh->rh_net != iface->i_caddr.sat_addr.s_net) { 119 LOG(log_error, logtype_atalkd, "rtmp_config net mismatch %u != %u", 120 ntohs( rh->rh_net ), 121 ntohs( iface->i_addr.sat_addr.s_net )); 122 return 1; 123 } 124 iface->i_addr.sat_addr.s_net = rh->rh_net; 125 126 /* 127 * It is possible that we will corrupt our route database 128 * by just forcing this change. XXX 129 */ 130 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = rh->rh_net; 131 132 setaddr( iface, IFACE_PHASE1, iface->i_addr.sat_addr.s_net, 133 iface->i_addr.sat_addr.s_node, rh->rh_net, rh->rh_net ); 134 stabletimer = UNSTABLE; 135 } 136 137 /* add addr to loopback route */ 138 if ((cc = looproute( iface, RTMP_ADD )) < 0 ) 139 return -1; 140 141 if (cc) { 142 LOG(log_error, logtype_atalkd, "rtmp_config: can't route %u.%u to loopback: %s", 143 ntohs( iface->i_addr.sat_addr.s_net ), 144 iface->i_addr.sat_addr.s_node, 145 strerror(errno) ); 146 } 147 148 LOG(log_info, logtype_atalkd, "rtmp_config configured %s", iface->i_name ); 149 iface->i_flags |= IFACE_CONFIG; 150 if ( iface == ciface ) { 151 ciface = ciface->i_next; 152 bootaddr( ciface ); 153 } 154 155 return 0; 156} 157 158/* 159 * Delete rtmp from the per-interface in-use table, remove all 160 * zone references, and remove the route from the kernel. 161 */ 162static void rtmp_delinuse(struct rtmptab *rtmp) 163{ 164 struct rtmptab *irt; 165 166 irt = rtmp->rt_gate->g_iface->i_rt; 167 if ( irt->rt_inext == rtmp ) { /* first */ 168 if ( rtmp->rt_iprev == rtmp ) { /* only */ 169 irt->rt_inext = NULL; 170 } else { 171 irt->rt_inext = rtmp->rt_inext; 172 rtmp->rt_inext->rt_iprev = rtmp->rt_iprev; 173 } 174 } else { 175 if ( rtmp->rt_inext == NULL ) { /* last */ 176 rtmp->rt_iprev->rt_inext = NULL; 177 irt->rt_inext->rt_iprev = rtmp->rt_iprev; 178 } else { 179 rtmp->rt_iprev->rt_inext = rtmp->rt_inext; 180 rtmp->rt_inext->rt_iprev = rtmp->rt_iprev; 181 } 182 } 183 rtmp->rt_iprev = NULL; 184 rtmp->rt_inext = NULL; 185 186 /* remove zone map */ 187 rtmp_delzonemap(rtmp); 188 189 /* remove old route */ 190 gateroute( RTMP_DEL, rtmp ); 191} 192 193/* 194 * Add rtmp to the per-interface in-use table. No verification is done... 195 */ 196static void rtmp_addinuse( struct rtmptab *rtmp) 197{ 198 struct rtmptab *irt; 199 200 gateroute( RTMP_ADD, rtmp ); 201 202 irt = rtmp->rt_gate->g_iface->i_rt; 203 if ( irt->rt_inext == NULL ) { /* empty list */ 204 rtmp->rt_inext = NULL; 205 rtmp->rt_iprev = rtmp; 206 irt->rt_inext = rtmp; 207 } else { 208 rtmp->rt_inext = irt->rt_inext; 209 rtmp->rt_iprev = irt->rt_inext->rt_iprev; 210 irt->rt_inext->rt_iprev = rtmp; 211 irt->rt_inext = rtmp; 212 } 213} 214 215 216/* 217 * Change the zone mapping to replace "from" with "to". This code assumes 218 * the consistency of both the route -> zone map and the zone -> route map. 219 * This is probably a bad idea. How can we insure that the data is good 220 * at this point? What do we do if we get several copies of a route in 221 * an RTMP packet? 222 */ 223static int rtmp_copyzones( struct rtmptab *to,struct rtmptab *from) 224{ 225 struct list *lz, *lr; 226 227 to->rt_zt = from->rt_zt; 228 from->rt_zt = NULL; 229 if ( from->rt_flags & RTMPTAB_HASZONES ) { 230 to->rt_flags |= RTMPTAB_HASZONES; 231 } 232 for ( lz = to->rt_zt; lz; lz = lz->l_next ) { 233 for ( lr = ((struct ziptab *)lz->l_data)->zt_rt; lr; lr = lr->l_next ) { 234 if ( (struct rtmptab *)lr->l_data == from ) { 235 lr->l_data = (void *)to; /* cast BS */ 236 break; 237 } 238 } 239 if ( lr == NULL ) { 240 LOG(log_error, logtype_atalkd, "rtmp_copyzones z -> r without r -> z, abort" ); 241 return -1; 242 } 243 } 244 245 return 0; 246} 247 248 249/* 250 * Remove rtmp from the in-use table and the per-gate table. 251 * Free any associated space. 252 */ 253void rtmp_free( struct rtmptab *rtmp) 254{ 255 struct gate *gate; 256 257 LOG(log_info, logtype_atalkd, "rtmp_free: %u-%u", ntohs(rtmp->rt_firstnet), 258 ntohs(rtmp->rt_lastnet)); 259 if ( rtmp->rt_iprev ) { 260 rtmp_delinuse( rtmp ); 261 } 262 263 /* remove from per-gate */ 264 gate = rtmp->rt_gate; 265 if ( gate->g_rt == rtmp ) { /* first */ 266 if ( rtmp->rt_prev == rtmp ) { /* only */ 267 gate->g_rt = NULL; 268 } else { 269 gate->g_rt = rtmp->rt_next; 270 rtmp->rt_next->rt_prev = rtmp->rt_prev; 271 } 272 } else { 273 if ( rtmp->rt_next == NULL ) { /* last */ 274 rtmp->rt_prev->rt_next = NULL; 275 gate->g_rt->rt_prev = rtmp->rt_prev; 276 } else { 277 rtmp->rt_prev->rt_next = rtmp->rt_next; 278 rtmp->rt_next->rt_prev = rtmp->rt_prev; 279 } 280 } 281 282 free( rtmp ); 283} 284 285 286/* 287 * Find a replacement for "replace". If we can't find a replacement, 288 * return 1. If we do find a replacement, return 0. -1 on error. 289 */ 290int rtmp_replace(struct rtmptab *replace) 291{ 292 struct interface *iface; 293 struct gate *gate; 294 struct rtmptab *rtmp, *found = NULL; 295 296 LOG(log_info, logtype_atalkd, "rtmp_replace %u-%u", ntohs(replace->rt_firstnet), 297 ntohs(replace->rt_lastnet)); 298 for ( iface = interfaces; iface; iface = iface->i_next ) { 299 if ((replace->rt_iface != iface) && 300 ((iface->i_flags & IFACE_ISROUTER) == 0)) 301 continue; 302 303 for ( gate = iface->i_gate; gate; gate = gate->g_next ) { 304 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) { 305 if ( rtmp->rt_firstnet == replace->rt_firstnet && 306 rtmp->rt_lastnet == replace->rt_lastnet ) { 307 if ( found == NULL || rtmp->rt_hops < found->rt_hops ) { 308 found = rtmp; 309 } 310 break; 311 } 312 } 313 } 314 } 315 316 if ( found != replace ) { 317 if (rtmp_copyzones( found, replace ) < 0) 318 return -1; 319 rtmp_delinuse( replace ); 320 rtmp_addinuse( found ); 321 if ( replace->rt_state == RTMPTAB_BAD ) { 322 rtmp_free( replace ); 323 } 324 return( 0 ); 325 } else { 326 if ( replace->rt_hops == RTMPHOPS_POISON ) { 327 gateroute( RTMP_DEL, replace ); 328 } 329 return( 1 ); 330 } 331} 332 333 334static int rtmp_new(struct rtmptab *rtmp) 335{ 336 struct interface *i; 337 struct rtmptab *r; 338 extern int newrtmpdata; 339 340 newrtmpdata = 1; 341 342 /* 343 * Do we already have a gateway for this route? 344 */ 345 for ( i = interfaces; i; i = i->i_next ) { 346 if ((rtmp->rt_iface != i) && 347 ((i->i_flags & IFACE_ISROUTER) == 0)) 348 continue; 349 350 for ( r = i->i_rt; r; r = r->rt_inext ) { 351 /* Should check RTMPTAB_EXTENDED here. XXX */ 352 if (( ntohs( r->rt_firstnet ) <= ntohs( rtmp->rt_firstnet ) && 353 ntohs( r->rt_lastnet ) >= ntohs( rtmp->rt_firstnet )) || 354 ( ntohs( r->rt_firstnet ) <= ntohs( rtmp->rt_lastnet ) && 355 ntohs( r->rt_lastnet ) >= ntohs( rtmp->rt_lastnet ))) { 356 break; 357 } 358 } 359 if ( r ) { 360 break; 361 } 362 } 363 364 /* 365 * This part of this routine is almost never run. 366 */ 367 if ( i ) { /* can we get here without r being set? */ 368 if ( r->rt_firstnet != rtmp->rt_firstnet || 369 r->rt_lastnet != rtmp->rt_lastnet ) { 370 LOG(log_info, logtype_atalkd, "rtmp_new netrange mismatch %u-%u != %u-%u", 371 ntohs( r->rt_firstnet ), ntohs( r->rt_lastnet ), 372 ntohs( rtmp->rt_firstnet ), ntohs( rtmp->rt_lastnet )); 373 return 1; 374 } 375 376 /* 377 * Note that our whole methodology is wrong, if we want to do 378 * route "load balancing." This entails changing our route 379 * each time we receive a tuple of equal value. In fact, we can't 380 * do this, using our method, since we only check against in-use 381 * routes when a tuple is new from a router. 382 */ 383 if ( r->rt_hops < rtmp->rt_hops ) { 384 return 1; 385 } 386 387 if (rtmp_copyzones( rtmp, r ) < 0) 388 return -1; 389 rtmp_delinuse( r ); 390 } 391 392 rtmp_addinuse( rtmp ); 393 return 0; 394} 395 396 397int rtmp_packet(struct atport *ap, struct sockaddr_at *from, char *data, int len) 398{ 399 struct rtmp_head rh; 400 struct rtmp_tuple rt, xrt; 401 struct gate *gate; 402 struct interface *iface; 403 struct interface *iface2; 404 struct rtmptab *rtmp; 405 char *end, packet[ ATP_BUFSIZ ]; 406 int cc; 407 408 end = data + len; 409 410 if ( data >= end ) { 411 LOG(log_info, logtype_atalkd, "rtmp_packet no data" ); 412 return 1; 413 } 414 415 iface = ap->ap_iface; 416 417 /* linux 2.6 sends broadcast queries to the first available socket 418 (in our case the last configured) 419 try to find the right one. 420 Note: now a misconfigured or plugged router can broadcast 421 a wrong route 422 */ 423 for ( iface2 = interfaces; iface2; iface2 = iface2->i_next ) { 424 if ( iface2->i_rt && from->sat_addr.s_net >= iface2->i_rt->rt_firstnet && 425 from->sat_addr.s_net <= iface2->i_rt->rt_lastnet) 426 { 427 iface = iface2; 428 } 429 } 430 /* end of linux 2.6 workaround */ 431 432 /* ignore our own packets */ 433 if ( from->sat_addr.s_net == iface->i_addr.sat_addr.s_net && 434 from->sat_addr.s_node == iface->i_addr.sat_addr.s_node ) { 435 return 0; 436 } 437 438 switch( *data++ ) { 439 case DDPTYPE_RTMPRD : 440 /* 441 * Response and Data. 442 */ 443 if ( data + sizeof( struct rtmprdhdr ) > end ) { 444 LOG(log_info, logtype_atalkd, "rtmp_packet no data header" ); 445 return 1; 446 } 447 memcpy( &rh, data, sizeof( struct rtmprdhdr )); 448 data += sizeof( struct rtmprdhdr ); 449 450 /* check rh address against from address */ 451 if ( rh.rh_nodelen != 8 ) { 452 LOG(log_info, logtype_atalkd, "rtmp_packet bad node len (%d)", rh.rh_nodelen ); 453 return 1; 454 } 455 if (( from->sat_addr.s_net != 0 && 456 from->sat_addr.s_net != rh.rh_net ) || 457 from->sat_addr.s_node != rh.rh_node ) { 458 LOG(log_info, logtype_atalkd, "rtmp_packet address mismatch" ); 459 return 1; 460 } 461 462 if (( iface->i_flags & ( IFACE_ADDR|IFACE_CONFIG )) == IFACE_ADDR ) { 463 if ( iface->i_flags & IFACE_NOROUTER ) { 464 /* remove addr to loopback route */ 465 if ((cc = looproute( iface, RTMP_DEL )) < 0) { 466 LOG(log_error, logtype_atalkd, "rtmp_packet: looproute"); 467 return -1; 468 } 469 470 if (cc) 471 LOG(log_error, logtype_atalkd, "rtmp_packet: can't remove loopback: %s", 472 strerror(errno) ); 473 474 iface->i_flags &= ~IFACE_NOROUTER; 475 iface->i_time = 0; 476 LOG(log_info, logtype_atalkd, "rtmp_packet router has become available" ); 477 } 478 if ( iface->i_flags & IFACE_PHASE1 ) { 479 if (rtmp_config( &rh, iface ) < 0) { 480 LOG(log_error, logtype_atalkd, "rtmp_packet: rtmp_config"); 481 return -1; 482 } 483 } else if (zip_getnetinfo( iface ) < 0) { 484 LOG(log_error, logtype_atalkd, "rtmp_packet: zip_getnetinfo"); 485 return -1; 486 } 487 return 0; 488 } 489 490 if (( iface->i_flags & IFACE_CONFIG ) == 0 ) { 491 return 0; 492 } 493 494 /* 495 * Parse first tuple. For phase 2, verify that net is correct. 496 */ 497 if ( data + SZ_RTMPTUPLE > end ) { 498 LOG(log_info, logtype_atalkd, "rtmp_packet missing first tuple" ); 499 return 1; 500 } 501 memcpy( &rt, data, SZ_RTMPTUPLE ); 502 data += SZ_RTMPTUPLE; 503 504 if ( rt.rt_net == 0 ) { 505 if ( rt.rt_dist != 0x82 ) { 506 LOG(log_info, logtype_atalkd, "rtmp_packet bad phase 1 version" ); 507 return 1; 508 } 509 510 /* 511 * Grab the next tuple, since we don't want to pass the version 512 * number to the parsing code. We're assuming that there are 513 * no extended tuples in this packet. 514 */ 515 if ( data + SZ_RTMPTUPLE > end ) { 516 LOG(log_info, logtype_atalkd, "rtmp_packet missing second tuple" ); 517 return 1; 518 } 519 memcpy( &rt, data, SZ_RTMPTUPLE ); 520 data += SZ_RTMPTUPLE; 521 } else if ( rt.rt_dist & 0x80 ) { 522 if ( data + SZ_RTMPTUPLE > end ) { 523 LOG(log_info, logtype_atalkd, "rtmp_packet missing first range-end" ); 524 return 1; 525 } 526 memcpy( &xrt, data, SZ_RTMPTUPLE ); 527 data += SZ_RTMPTUPLE; 528 529 if ( xrt.rt_dist != 0x82 ) { 530 LOG(log_info, logtype_atalkd, "rtmp_packet bad phase 2 version" ); 531 return 1; 532 } 533 534 /* 535 * Check for net range conflict. 536 */ 537 if ( rt.rt_net != iface->i_rt->rt_firstnet || 538 xrt.rt_net != iface->i_rt->rt_lastnet ) { 539 LOG(log_info, logtype_atalkd, "rtmp_packet interface mismatch" ); 540 return 1; 541 } 542 } else { 543#ifdef PHASE1NET 544 /* 545 * Gatorboxes put a net number in the first tuple, even on 546 * phase 1 nets. This is wrong, but since we've got it, we 547 * might just as well check it. 548 if ( rt.rt_net != iface->i_rt->rt_firstnet || 549 rt.rt_net != iface->i_rt->rt_lastnet ) { 550 LOG(log_info, logtype_atalkd, "rtmp_packet phase 1 interface mismatch" ); 551 return 1; 552 } 553 */ 554#else /* PHASE1NET */ 555 LOG(log_info, logtype_atalkd, "rtmp_packet bad first tuple" ); 556 return 1; 557#endif /* PHASE1NET */ 558 } 559 560 /* 561 * Find gateway. 562 */ 563 for ( gate = iface->i_gate; gate; gate = gate->g_next ) { 564 if ( gate->g_sat.sat_addr.s_net == from->sat_addr.s_net && 565 gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) { 566 break; 567 } 568 } 569 if ( !gate ) { /* new gateway */ 570 if (( gate = (struct gate *)malloc( sizeof( struct gate ))) == NULL ) { 571 LOG(log_error, logtype_atalkd, "rtmp_packet: malloc: %s", strerror(errno) ); 572 return -1; 573 } 574 gate->g_next = iface->i_gate; 575 gate->g_prev = NULL; 576 gate->g_rt = NULL; 577 gate->g_iface = iface; /* need this? */ 578 gate->g_sat = *from; 579 if ( iface->i_gate ) { 580 iface->i_gate->g_prev = gate; 581 } 582 iface->i_gate = gate; 583 LOG(log_info, logtype_atalkd, "rtmp_packet gateway %u.%u up", 584 ntohs( gate->g_sat.sat_addr.s_net ), 585 gate->g_sat.sat_addr.s_node ); 586 } 587 588 /* 589 * Reset the timeout on this gateway. We'll remove the gateway 590 * entry, if the timeout gets to RTMPTAB_BAD. 591 */ 592 gate->g_state = RTMPTAB_GOOD; 593 594 /* 595 * Parse remaining tuples. 596 */ 597 for (;;) { 598 /* 599 * Is route on this gateway? 600 */ 601 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) { 602 if ( ntohs( rtmp->rt_firstnet ) <= ntohs( rt.rt_net ) && 603 ntohs( rtmp->rt_lastnet ) >= ntohs( rt.rt_net )) { 604 break; 605 } 606 if (( rt.rt_dist & 0x80 ) && 607 ntohs( rtmp->rt_firstnet ) <= ntohs( xrt.rt_net ) && 608 ntohs( rtmp->rt_lastnet ) >= ntohs( xrt.rt_net )) { 609 break; 610 } 611 } 612 613 if ( rtmp ) { /* found it */ 614 /* 615 * Check for range conflicts. (This is getting a little 616 * ugly.) 617 */ 618 if ( rtmp->rt_firstnet != rt.rt_net ) { 619 LOG(log_info, logtype_atalkd, "rtmp_packet firstnet mismatch %u!=%u", 620 ntohs( rtmp->rt_firstnet ), ntohs( rt.rt_net )); 621 return 1; 622 } 623 if ( rt.rt_dist & 0x80 ) { 624 if (( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) { 625 LOG(log_info, logtype_atalkd, "rtmp_packet extended mismatch %u", 626 ntohs( rtmp->rt_firstnet )); 627 return 1; 628 } 629 if ( rtmp->rt_lastnet != xrt.rt_net ) { 630 LOG(log_info, logtype_atalkd, "rtmp_packet lastnet mismatch %u!=%u", 631 ntohs( rtmp->rt_lastnet ), ntohs( xrt.rt_net )); 632 return 1; 633 } 634 } else { 635 if ( rtmp->rt_flags & RTMPTAB_EXTENDED ) { 636 LOG(log_info, logtype_atalkd, "rtmp_packet !extended mismatch %u", 637 ntohs( rtmp->rt_firstnet )); 638 return 1; 639 } 640 if ( rtmp->rt_lastnet != rt.rt_net ) { 641 LOG(log_info, logtype_atalkd, "rtmp_packet lastnet mismatch %u!=%u", 642 ntohs( rtmp->rt_lastnet ), ntohs( rt.rt_net )); 643 return 1; 644 } 645 } 646 647 rtmp->rt_state = RTMPTAB_GOOD; 648 649 /* 650 * Check hop count. If the count has changed, update 651 * the routing database. 652 */ 653 if (( rtmp->rt_hops != ( rt.rt_dist & 0x7f ) + 1 ) && 654 ( rtmp->rt_hops != RTMPHOPS_POISON || 655 ( rt.rt_dist & 0x7f ) + 1 <= RTMPHOPS_MAX )) { 656 if ( rtmp->rt_iprev ) { /* route is in use */ 657 if ( rtmp->rt_hops > ( rt.rt_dist & 0x7f ) + 1 ) { 658 /* 659 * If this was POISON, we've deleted it from 660 * the kernel. Add it back in. 661 */ 662 if ( rtmp->rt_hops == RTMPHOPS_POISON ) { 663 gateroute( RTMP_ADD, rtmp ); 664 } 665 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1; 666 } else { 667 /* 668 * Hop count has gone up for this route. 669 * Search for a new best route. If we can't 670 * find one, just keep this route. "poison" 671 * route are deleted in as_timer(). 672 */ 673 if (( rt.rt_dist & 0x7f ) + 1 > RTMPHOPS_MAX ) { 674 rtmp->rt_hops = RTMPHOPS_POISON; 675 } else { 676 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1; 677 } 678 if (rtmp_replace( rtmp ) < 0) { 679 LOG(log_error, logtype_atalkd, "rtmp_packet: rtmp_replace"); 680 return -1; 681 } 682 } 683 } else { /* route not in use */ 684 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1; 685 if ( rtmp->rt_hops > ( rt.rt_dist & 0x7f ) + 1 ) { 686 if (rtmp_new( rtmp ) < 0) { 687 LOG(log_error, logtype_atalkd, "rtmp_packet: rtmp_new"); 688 return -1; 689 } 690 } 691 } 692 } 693 694 /* 695 * Make the *next* node the head, since 696 * we're not likely to be asked for the same tuple twice 697 * in a row. 698 */ 699 if ( rtmp->rt_next != NULL ) { 700 gate->g_rt->rt_prev->rt_next = gate->g_rt; 701 gate->g_rt = rtmp->rt_next; 702 rtmp->rt_next = NULL; 703 } 704 } else if (( rt.rt_dist & 0x7f ) + 1 > RTMPHOPS_MAX ) { 705 LOG(log_info, logtype_atalkd, "rtmp_packet bad hop count from %u.%u for %u", 706 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node, 707 ntohs( rt.rt_net )); 708 } else { /* new for router */ 709 if (( rtmp = newrt(iface)) == NULL ) { 710 LOG(log_error, logtype_atalkd, "rtmp_packet: newrt: %s", strerror(errno) ); 711 return -1; 712 } 713 rtmp->rt_firstnet = rt.rt_net; 714 if ( rt.rt_dist & 0x80 ) { 715 rtmp->rt_lastnet = xrt.rt_net; 716 rtmp->rt_flags = RTMPTAB_EXTENDED; 717 } else { 718 rtmp->rt_lastnet = rt.rt_net; 719 } 720 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1; 721 rtmp->rt_state = RTMPTAB_GOOD; 722 rtmp->rt_gate = gate; 723 724 /* 725 * Add rtmptab entry to end of list (leave head alone). 726 */ 727 if ( gate->g_rt == NULL ) { 728 rtmp->rt_prev = rtmp; 729 gate->g_rt = rtmp; 730 } else { 731 rtmp->rt_prev = gate->g_rt->rt_prev; 732 gate->g_rt->rt_prev->rt_next = rtmp; 733 gate->g_rt->rt_prev = rtmp; 734 } 735 736 if (rtmp_new( rtmp ) < 0) { 737 LOG(log_error, logtype_atalkd, "rtmp_packet: rtmp_new"); 738 return -1; 739 } 740 } 741 742 if ( data + SZ_RTMPTUPLE > end ) { 743 break; 744 } 745 memcpy( &rt, data, SZ_RTMPTUPLE ); 746 data += SZ_RTMPTUPLE; 747 if ( rt.rt_dist & 0x80 ) { 748 if ( data + SZ_RTMPTUPLE > end ) { 749 LOG(log_info, logtype_atalkd, "rtmp_packet missing range-end" ); 750 return 1; 751 } 752 memcpy( &xrt, data, SZ_RTMPTUPLE ); 753 data += SZ_RTMPTUPLE; 754 } 755 } 756 757 /* 758 * Make sure we've processed the whole packet. 759 */ 760 if ( data != end ) { 761 LOG(log_info, logtype_atalkd, "rtmp_packet length and count mismatch" ); 762 } 763 break; 764 765 case DDPTYPE_RTMPR : 766 /* 767 * Request and RDR. 768 */ 769 if (((iface->i_flags & IFACE_ISROUTER) == 0) || 770 iface->i_rt->rt_zt == NULL || 771 ( iface->i_flags & IFACE_CONFIG ) == 0 ) { 772 return 0; 773 } 774 if ( *data == 1 ) { 775 data = packet; 776 *data++ = DDPTYPE_RTMPRD; 777 rh.rh_net = iface->i_addr.sat_addr.s_net; 778 rh.rh_nodelen = 8; 779 rh.rh_node = iface->i_addr.sat_addr.s_node; 780 memcpy( data, &rh, sizeof( struct rtmp_head )); 781 data += sizeof( struct rtmp_head ); 782 783 if ( iface->i_flags & IFACE_PHASE2 ) { 784 rt.rt_net = iface->i_rt->rt_firstnet; 785 rt.rt_dist = 0x80; 786 memcpy( data, &rt, SZ_RTMPTUPLE ); 787 data += SZ_RTMPTUPLE; 788 789 rt.rt_net = iface->i_rt->rt_lastnet; 790 rt.rt_dist = 0x82; 791 memcpy( data, &rt, SZ_RTMPTUPLE ); 792 data += SZ_RTMPTUPLE; 793 } 794 if ( sendto( ap->ap_fd, packet, data - packet, 0, 795 (struct sockaddr *)from, 796 sizeof( struct sockaddr_at )) < 0 ) { 797 LOG(log_error, logtype_atalkd, "as_timer sendto: %s", strerror(errno) ); 798 } 799 } else if ( *data == 2 || *data == 3 ) { 800#ifdef DEBUG 801 printf( "rtmp_packet rdr (%d) from %u.%u\n", 802 *data, ntohs( from->sat_addr.s_net ), 803 from->sat_addr.s_node ); 804#endif /* DEBUG */ 805 } else { 806 LOG(log_info, logtype_atalkd, "rtmp_packet unknown request from %u.%u", 807 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node ); 808 } 809 break; 810 811 default : 812 LOG(log_info, logtype_atalkd, "rtmp_packet bad ddp type from %u.%u", 813 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node ); 814 return 0; 815 } 816 817 return 0; 818} 819 820int rtmp_request( struct interface *iface) 821{ 822 struct sockaddr_at sat; 823 struct atport *ap; 824 char *data, packet[ 2 ]; 825 826 LOG(log_info, logtype_atalkd, "rtmp_request for %s", iface->i_name ); 827 828 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) { 829 if ( ap->ap_packet == rtmp_packet ) { 830 break; 831 } 832 } 833 if ( ap == NULL ) { 834 LOG(log_error, logtype_atalkd, "rtmp_request can't find rtmp socket!" ); 835 return -1; 836 } 837 838 data = packet; 839 *data++ = DDPTYPE_RTMPR; 840 *data++ = RTMPROP_REQUEST; 841 842 /* 843 * There is a problem with the net zero "hint" hack. 844 */ 845 memset( &sat, 0, sizeof( struct sockaddr_at )); 846#ifdef BSD4_4 847 sat.sat_len = sizeof( struct sockaddr_at ); 848#endif /* BSD4_4 */ 849 sat.sat_family = AF_APPLETALK; 850 sat.sat_addr.s_net = iface->i_addr.sat_addr.s_net; 851 sat.sat_addr.s_node = ATADDR_BCAST; 852 sat.sat_port = ap->ap_port; 853 if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat, 854 sizeof( struct sockaddr_at )) < 0 ) { 855 LOG(log_error, logtype_atalkd, "rtmp_request sendto: %s", strerror(errno) ); 856 return -1; 857 } 858 return 0; 859} 860 861 862int looproute(struct interface *iface, unsigned int cmd) 863{ 864 struct sockaddr_at dst, loop; 865 866 if ( cmd == RTMP_DEL && ( iface->i_flags & IFACE_LOOP ) == 0 ) { 867 LOG(log_error, logtype_atalkd, "looproute panic no route" ); 868 return -1; 869 } 870 871 if ( cmd == RTMP_ADD && ( iface->i_flags & IFACE_LOOP )) { 872 LOG(log_error, logtype_atalkd, "looproute panic two routes" ); 873 return -1; 874 } 875 876 memset( &dst, 0, sizeof( struct sockaddr_at )); 877#ifdef BSD4_4 878 dst.sat_len = sizeof( struct sockaddr_at ); 879#endif /* BSD4_4 */ 880 dst.sat_family = AF_APPLETALK; 881 dst.sat_addr.s_net = iface->i_addr.sat_addr.s_net; 882 dst.sat_addr.s_node = iface->i_addr.sat_addr.s_node; 883 memset( &loop, 0, sizeof( struct sockaddr_at )); 884#ifdef BSD4_4 885 loop.sat_len = sizeof( struct sockaddr_at ); 886#endif /* BSD4_4 */ 887 loop.sat_family = AF_APPLETALK; 888 loop.sat_addr.s_net = htons( ATADDR_ANYNET ); 889 loop.sat_addr.s_node = ATADDR_ANYNODE; 890 891#ifndef BSD4_4 892 if ( route( cmd, 893 (struct sockaddr *) &dst, 894 (struct sockaddr *) &loop, 895 RTF_UP | RTF_HOST ) ) { 896 return( 1 ); 897 } 898#else /* ! BSD4_4 */ 899 if ( route( cmd, 900 (struct sockaddr_at *) &dst, 901 (struct sockaddr_at *) &loop, 902 RTF_UP | RTF_HOST ) ) { 903 return ( 1); 904 } 905#endif /* BSD4_4 */ 906 if ( cmd == RTMP_ADD ) { 907 iface->i_flags |= IFACE_LOOP; 908 } 909 if ( cmd == RTMP_DEL ) { 910 iface->i_flags &= ~IFACE_LOOP; 911 } 912 return( 0 ); 913} 914 915int gateroute(unsigned int command, struct rtmptab *rtmp) 916{ 917 struct sockaddr_at dst, gate; 918 unsigned short net; 919 920 if ( command == RTMP_DEL && ( rtmp->rt_flags & RTMPTAB_ROUTE ) == 0 ) { 921 return( -1 ); 922 } 923 if ( command == RTMP_ADD && ( rtmp->rt_flags & RTMPTAB_ROUTE )) { 924 return( -1 ); 925 } 926 927 net = ntohs( rtmp->rt_firstnet ); 928 /* 929 * Since we will accept routes from gateways who advertise their 930 * address as 0.YY, we must munge the gateway address we give to 931 * the kernel. Otherwise, we'll get a bunch of routes to the loop 932 * back interface, and who wants that? 933 */ 934 memset( &gate, 0, sizeof( struct sockaddr_at )); 935#ifdef BSD4_4 936 gate.sat_len = sizeof( struct sockaddr_at ); 937#endif /* BSD4_4 */ 938 gate.sat_family = AF_APPLETALK; 939 gate.sat_addr.s_net = rtmp->rt_gate->g_sat.sat_addr.s_net; 940 gate.sat_addr.s_node = rtmp->rt_gate->g_sat.sat_addr.s_node; 941 if ( gate.sat_addr.s_net == 0 ) { 942 gate.sat_addr.s_net = net; 943 } 944 945 memset( &dst, 0, sizeof( struct sockaddr_at )); 946#ifdef BSD4_4 947 dst.sat_len = sizeof( struct sockaddr_at ); 948#endif /* BSD4_4 */ 949 dst.sat_family = AF_APPLETALK; 950 dst.sat_addr.s_node = ATADDR_ANYNODE; 951 952 do { 953 dst.sat_addr.s_net = htons( net ); 954#ifndef BSD4_4 955 if ( route( command, 956 (struct sockaddr *) &dst, 957 (struct sockaddr *) &gate, 958 RTF_UP | RTF_GATEWAY )) { 959 LOG(log_error, logtype_atalkd, "route: %u -> %u.%u: %s", net, 960 ntohs( gate.sat_addr.s_net ), gate.sat_addr.s_node, 961 strerror(errno) ); 962 continue; 963 } 964#else /* ! BSD4_4 */ 965 if ( route( command, 966 (struct sockaddr_at *) &dst, 967 (struct sockaddr_at *) &gate, 968 RTF_UP | RTF_GATEWAY )) { 969 LOG(log_error, logtype_atalkd, "route: %u -> %u.%u: %s", net, 970 ntohs( gate.sat_addr.s_net ), gate.sat_addr.s_node, strerror(errno) ); 971 continue; 972 } 973#endif /* ! BSD4_4 */ 974 } while ( net++ < ntohs( rtmp->rt_lastnet )); 975 976 if ( command == RTMP_ADD ) { 977 rtmp->rt_flags |= RTMPTAB_ROUTE; 978 } 979 if ( command == RTMP_DEL ) { 980 rtmp->rt_flags &= ~RTMPTAB_ROUTE; 981 } 982 983 return( 0 ); 984} 985 986 struct rtmptab * 987newrt(const struct interface *iface) 988{ 989 struct rtmptab *rtmp; 990 991 if (( rtmp = (struct rtmptab *)calloc(1, sizeof(struct rtmptab))) == NULL ) { 992 return( NULL ); 993 } 994 995 rtmp->rt_iface = iface; 996 return( rtmp ); 997} 998