2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
12 #include <sys/syslog.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/socket.h>
16 #include <sys/ioctl.h>
18 #include <net/route.h>
19 #include <netatalk/endian.h>
20 #include <netatalk/at.h>
23 #include <sys/sockio.h>
26 #include <atalk/ddp.h>
27 #include <atalk/atp.h>
28 #include <atalk/rtmp.h>
30 #include "interface.h"
39 void rtmp_delzonemap(rtmp)
42 struct list *lz, *flz, *lr, *flr;
46 while ( lz ) { /* for each zone */
47 zt = (struct ziptab *)lz->l_data;
49 while ( lr ) { /* for each route */
50 if ( (struct rtmptab *)lr->l_data == rtmp ) {
51 if ( lr->l_prev == NULL ) { /* head */
52 if ( lr->l_next == NULL ) { /* last route in zone */
53 if ( zt->zt_prev == NULL ) {
56 zt->zt_prev->zt_next = zt->zt_next;
58 if ( zt->zt_next == NULL ) {
59 ziplast = zt->zt_prev;
61 zt->zt_next->zt_prev = zt->zt_prev;
67 zt->zt_rt = lr->l_next;
70 lr->l_prev->l_next = lr->l_next;
72 if ( lr->l_next != NULL ) {
73 lr->l_next->l_prev = lr->l_prev;
91 * Complete configuration for phase 1 interface using RTMP information.
93 static int rtmp_config( rh, iface )
95 struct interface *iface;
97 extern int stabletimer;
101 * If we're configuring a phase 2 interface, don't complete
102 * configuration with RTMP.
104 if ( iface->i_flags & IFACE_PHASE2 ) {
105 syslog( LOG_INFO, "rtmp_config ignoring data" );
110 * Check our seed information, and reconfigure.
112 if ( rh->rh_net != iface->i_addr.sat_addr.s_net ) {
113 if (( iface->i_flags & IFACE_SEED ) &&
114 rh->rh_net != iface->i_caddr.sat_addr.s_net) {
115 syslog( LOG_ERR, "rtmp_config net mismatch %u != %u",
117 ntohs( iface->i_addr.sat_addr.s_net ));
120 iface->i_addr.sat_addr.s_net = rh->rh_net;
123 * It is possible that we will corrupt our route database
124 * by just forcing this change. XXX
126 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = rh->rh_net;
128 setaddr( iface, IFACE_PHASE1, iface->i_addr.sat_addr.s_net,
129 iface->i_addr.sat_addr.s_node, rh->rh_net, rh->rh_net );
130 stabletimer = UNSTABLE;
133 /* add addr to loopback route */
134 if ((cc = looproute( iface, RTMP_ADD )) < 0 )
138 syslog( LOG_ERR, "rtmp_config: can't route %u.%u to loopback: %m",
139 ntohs( iface->i_addr.sat_addr.s_net ),
140 iface->i_addr.sat_addr.s_node );
143 syslog( LOG_INFO, "rtmp_config configured %s", iface->i_name );
144 iface->i_flags |= IFACE_CONFIG;
145 if ( iface == ciface ) {
146 ciface = ciface->i_next;
154 * Delete rtmp from the per-interface in-use table, remove all
155 * zone references, and remove the route from the kernel.
157 static void rtmp_delinuse( rtmp )
158 struct rtmptab *rtmp;
162 irt = rtmp->rt_gate->g_iface->i_rt;
163 if ( irt->rt_inext == rtmp ) { /* first */
164 if ( rtmp->rt_iprev == rtmp ) { /* only */
165 irt->rt_inext = NULL;
167 irt->rt_inext = rtmp->rt_inext;
168 rtmp->rt_inext->rt_iprev = rtmp->rt_iprev;
171 if ( rtmp->rt_inext == NULL ) { /* last */
172 rtmp->rt_iprev->rt_inext = NULL;
173 irt->rt_inext->rt_iprev = rtmp->rt_iprev;
175 rtmp->rt_iprev->rt_inext = rtmp->rt_inext;
176 rtmp->rt_inext->rt_iprev = rtmp->rt_iprev;
179 rtmp->rt_iprev = NULL;
180 rtmp->rt_inext = NULL;
182 /* remove zone map */
183 rtmp_delzonemap(rtmp);
185 /* remove old route */
186 gateroute( RTMP_DEL, rtmp );
190 * Add rtmp to the per-interface in-use table. No verification is done...
192 static void rtmp_addinuse( rtmp )
193 struct rtmptab *rtmp;
197 gateroute( RTMP_ADD, rtmp );
199 irt = rtmp->rt_gate->g_iface->i_rt;
200 if ( irt->rt_inext == NULL ) { /* empty list */
201 rtmp->rt_inext = NULL;
202 rtmp->rt_iprev = rtmp;
203 irt->rt_inext = rtmp;
205 rtmp->rt_inext = irt->rt_inext;
206 rtmp->rt_iprev = irt->rt_inext->rt_iprev;
207 irt->rt_inext->rt_iprev = rtmp;
208 irt->rt_inext = rtmp;
214 * Change the zone mapping to replace "from" with "to". This code assumes
215 * the consistency of both the route -> zone map and the zone -> route map.
216 * This is probably a bad idea. How can we insure that the data is good
217 * at this point? What do we do if we get several copies of a route in
220 static int rtmp_copyzones( to, from )
221 struct rtmptab *to, *from;
223 struct list *lz, *lr;
225 to->rt_zt = from->rt_zt;
227 if ( from->rt_flags & RTMPTAB_HASZONES ) {
228 to->rt_flags |= RTMPTAB_HASZONES;
230 for ( lz = to->rt_zt; lz; lz = lz->l_next ) {
231 for ( lr = ((struct ziptab *)lz->l_data)->zt_rt; lr; lr = lr->l_next ) {
232 if ( (struct rtmptab *)lr->l_data == from ) {
233 lr->l_data = (void *)to; /* cast BS */
238 syslog( LOG_ERR, "rtmp_copyzones z -> r without r -> z, abort" );
248 * Remove rtmp from the in-use table and the per-gate table.
249 * Free any associated space.
251 void rtmp_free( rtmp )
252 struct rtmptab *rtmp;
256 syslog(LOG_INFO, "rtmp_free: %u-%u", ntohs(rtmp->rt_firstnet),
257 ntohs(rtmp->rt_lastnet));
258 if ( rtmp->rt_iprev ) {
259 rtmp_delinuse( rtmp );
262 /* remove from per-gate */
263 gate = rtmp->rt_gate;
264 if ( gate->g_rt == rtmp ) { /* first */
265 if ( rtmp->rt_prev == rtmp ) { /* only */
268 gate->g_rt = rtmp->rt_next;
269 rtmp->rt_next->rt_prev = rtmp->rt_prev;
272 if ( rtmp->rt_next == NULL ) { /* last */
273 rtmp->rt_prev->rt_next = NULL;
274 gate->g_rt->rt_prev = rtmp->rt_prev;
276 rtmp->rt_prev->rt_next = rtmp->rt_next;
277 rtmp->rt_next->rt_prev = rtmp->rt_prev;
286 * Find a replacement for "replace". If we can't find a replacement,
287 * return 1. If we do find a replacement, return 0. -1 on error.
289 int rtmp_replace( replace )
290 struct rtmptab *replace;
292 struct interface *iface;
294 struct rtmptab *rtmp, *found = NULL;
296 syslog(LOG_INFO, "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))
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 ) {
316 if ( found != replace ) {
317 if (rtmp_copyzones( found, replace ) < 0)
319 rtmp_delinuse( replace );
320 rtmp_addinuse( found );
321 if ( replace->rt_state == RTMPTAB_BAD ) {
322 rtmp_free( replace );
326 if ( replace->rt_hops == RTMPHOPS_POISON ) {
327 gateroute( RTMP_DEL, replace );
334 static int rtmp_new( rtmp )
335 struct rtmptab *rtmp;
339 extern int newrtmpdata;
344 * Do we already have a gateway for this route?
346 for ( i = interfaces; i; i = i->i_next ) {
347 if ((rtmp->rt_iface != i) &&
348 ((i->i_flags & IFACE_ISROUTER) == 0))
351 for ( r = i->i_rt; r; r = r->rt_inext ) {
352 /* Should check RTMPTAB_EXTENDED here. XXX */
353 if (( ntohs( r->rt_firstnet ) <= ntohs( rtmp->rt_firstnet ) &&
354 ntohs( r->rt_lastnet ) >= ntohs( rtmp->rt_firstnet )) ||
355 ( ntohs( r->rt_firstnet ) <= ntohs( rtmp->rt_lastnet ) &&
356 ntohs( r->rt_lastnet ) >= ntohs( rtmp->rt_lastnet ))) {
366 * This part of this routine is almost never run.
368 if ( i ) { /* can we get here without r being set? */
369 if ( r->rt_firstnet != rtmp->rt_firstnet ||
370 r->rt_lastnet != rtmp->rt_lastnet ) {
371 syslog( LOG_INFO, "rtmp_new netrange mismatch %u-%u != %u-%u",
372 ntohs( r->rt_firstnet ), ntohs( r->rt_lastnet ),
373 ntohs( rtmp->rt_firstnet ), ntohs( rtmp->rt_lastnet ));
378 * Note that our whole methodology is wrong, if we want to do
379 * route "load balancing." This entails changing our route
380 * each time we receive a tuple of equal value. In fact, we can't
381 * do this, using our method, since we only check against in-use
382 * routes when a tuple is new from a router.
384 if ( r->rt_hops < rtmp->rt_hops ) {
388 if (rtmp_copyzones( rtmp, r ) < 0)
393 rtmp_addinuse( rtmp );
398 int rtmp_packet( ap, from, data, len )
400 struct sockaddr_at *from;
405 struct rtmp_tuple rt, xrt;
407 struct interface *iface;
408 struct rtmptab *rtmp;
409 char *end, packet[ ATP_BUFSIZ ];
415 syslog( LOG_INFO, "rtmp_packet no data" );
419 iface = ap->ap_iface;
421 /* ignore our own packets */
422 if ( from->sat_addr.s_net == iface->i_addr.sat_addr.s_net &&
423 from->sat_addr.s_node == iface->i_addr.sat_addr.s_node ) {
428 case DDPTYPE_RTMPRD :
432 if ( data + sizeof( struct rtmprdhdr ) > end ) {
433 syslog( LOG_INFO, "rtmp_packet no data header" );
436 memcpy( &rh, data, sizeof( struct rtmprdhdr ));
437 data += sizeof( struct rtmprdhdr );
439 /* check rh address against from address */
440 if ( rh.rh_nodelen != 8 ) {
441 syslog( LOG_INFO, "rtmp_packet bad node len (%d)", rh.rh_nodelen );
444 if (( from->sat_addr.s_net != 0 &&
445 from->sat_addr.s_net != rh.rh_net ) ||
446 from->sat_addr.s_node != rh.rh_node ) {
447 syslog( LOG_INFO, "rtmp_packet address mismatch" );
451 if (( iface->i_flags & ( IFACE_ADDR|IFACE_CONFIG )) == IFACE_ADDR ) {
452 if ( iface->i_flags & IFACE_NOROUTER ) {
453 /* remove addr to loopback route */
454 if ((cc = looproute( iface, RTMP_DEL )) < 0) {
455 syslog(LOG_ERR, "rtmp_packet: looproute");
460 syslog( LOG_ERR, "rtmp_packet: can't remove loopback: %m" );
462 iface->i_flags &= ~IFACE_NOROUTER;
464 syslog( LOG_INFO, "rtmp_packet router has become available" );
466 if ( iface->i_flags & IFACE_PHASE1 ) {
467 if (rtmp_config( &rh, iface ) < 0) {
468 syslog(LOG_ERR, "rtmp_packet: rtmp_config");
471 } else if (zip_getnetinfo( iface ) < 0) {
472 syslog(LOG_ERR, "rtmp_packet: zip_getnetinfo");
478 if (( iface->i_flags & IFACE_CONFIG ) == 0 ) {
483 * Parse first tuple. For phase 2, verify that net is correct.
485 if ( data + SZ_RTMPTUPLE > end ) {
486 syslog( LOG_INFO, "rtmp_packet missing first tuple" );
489 memcpy( &rt, data, SZ_RTMPTUPLE );
490 data += SZ_RTMPTUPLE;
492 if ( rt.rt_net == 0 ) {
493 if ( rt.rt_dist != 0x82 ) {
494 syslog( LOG_INFO, "rtmp_packet bad phase 1 version" );
499 * Grab the next tuple, since we don't want to pass the version
500 * number to the parsing code. We're assuming that there are
501 * no extended tuples in this packet.
503 if ( data + SZ_RTMPTUPLE > end ) {
504 syslog( LOG_INFO, "rtmp_packet missing second tuple" );
507 memcpy( &rt, data, SZ_RTMPTUPLE );
508 data += SZ_RTMPTUPLE;
509 } else if ( rt.rt_dist & 0x80 ) {
510 if ( data + SZ_RTMPTUPLE > end ) {
511 syslog( LOG_INFO, "rtmp_packet missing first range-end" );
514 memcpy( &xrt, data, SZ_RTMPTUPLE );
515 data += SZ_RTMPTUPLE;
517 if ( xrt.rt_dist != 0x82 ) {
518 syslog( LOG_INFO, "rtmp_packet bad phase 2 version" );
523 * Check for net range conflict.
525 if ( rt.rt_net != iface->i_rt->rt_firstnet ||
526 xrt.rt_net != iface->i_rt->rt_lastnet ) {
527 syslog( LOG_INFO, "rtmp_packet interface mismatch" );
533 * Gatorboxes put a net number in the first tuple, even on
534 * phase 1 nets. This is wrong, but since we've got it, we
535 * might just as well check it.
536 if ( rt.rt_net != iface->i_rt->rt_firstnet ||
537 rt.rt_net != iface->i_rt->rt_lastnet ) {
538 syslog( LOG_INFO, "rtmp_packet phase 1 interface mismatch" );
543 syslog( LOG_INFO, "rtmp_packet bad first tuple" );
551 for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
552 if ( gate->g_sat.sat_addr.s_net == from->sat_addr.s_net &&
553 gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
557 if ( !gate ) { /* new gateway */
558 if (( gate = (struct gate *)malloc( sizeof( struct gate ))) == 0 ) {
559 syslog( LOG_ERR, "rtmp_packet: malloc: %m" );
562 gate->g_next = iface->i_gate;
565 gate->g_iface = iface; /* need this? */
567 if ( iface->i_gate ) {
568 iface->i_gate->g_prev = gate;
570 iface->i_gate = gate;
571 syslog( LOG_INFO, "rtmp_packet gateway %u.%u up",
572 ntohs( gate->g_sat.sat_addr.s_net ),
573 gate->g_sat.sat_addr.s_node );
577 * Reset the timeout on this gateway. We'll remove the gateway
578 * entry, if the timeout gets to RTMPTAB_BAD.
580 gate->g_state = RTMPTAB_GOOD;
583 * Parse remaining tuples.
587 * Is route on this gateway?
589 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
590 if ( ntohs( rtmp->rt_firstnet ) <= ntohs( rt.rt_net ) &&
591 ntohs( rtmp->rt_lastnet ) >= ntohs( rt.rt_net )) {
594 if (( rt.rt_dist & 0x80 ) &&
595 ntohs( rtmp->rt_firstnet ) <= ntohs( xrt.rt_net ) &&
596 ntohs( rtmp->rt_lastnet ) >= ntohs( xrt.rt_net )) {
601 if ( rtmp ) { /* found it */
603 * Check for range conflicts. (This is getting a little
606 if ( rtmp->rt_firstnet != rt.rt_net ) {
607 syslog( LOG_INFO, "rtmp_packet firstnet mismatch %u!=%u",
608 ntohs( rtmp->rt_firstnet ), ntohs( rt.rt_net ));
611 if ( rt.rt_dist & 0x80 ) {
612 if (( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
613 syslog( LOG_INFO, "rtmp_packet extended mismatch %u",
614 ntohs( rtmp->rt_firstnet ));
617 if ( rtmp->rt_lastnet != xrt.rt_net ) {
618 syslog( LOG_INFO, "rtmp_packet lastnet mismatch %u!=%u",
619 ntohs( rtmp->rt_lastnet ), ntohs( xrt.rt_net ));
623 if ( rtmp->rt_flags & RTMPTAB_EXTENDED ) {
624 syslog( LOG_INFO, "rtmp_packet !extended mismatch %u",
625 ntohs( rtmp->rt_firstnet ));
628 if ( rtmp->rt_lastnet != rt.rt_net ) {
629 syslog( LOG_INFO, "rtmp_packet lastnet mismatch %u!=%u",
630 ntohs( rtmp->rt_lastnet ), ntohs( rt.rt_net ));
635 rtmp->rt_state = RTMPTAB_GOOD;
638 * Check hop count. If the count has changed, update
639 * the routing database.
641 if (( rtmp->rt_hops != ( rt.rt_dist & 0x7f ) + 1 ) &&
642 ( rtmp->rt_hops != RTMPHOPS_POISON ||
643 ( rt.rt_dist & 0x7f ) + 1 <= RTMPHOPS_MAX )) {
644 if ( rtmp->rt_iprev ) { /* route is in use */
645 if ( rtmp->rt_hops > ( rt.rt_dist & 0x7f ) + 1 ) {
647 * If this was POISON, we've deleted it from
648 * the kernel. Add it back in.
650 if ( rtmp->rt_hops == RTMPHOPS_POISON ) {
651 gateroute( RTMP_ADD, rtmp );
653 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
656 * Hop count has gone up for this route.
657 * Search for a new best route. If we can't
658 * find one, just keep this route. "poison"
659 * route are deleted in as_timer().
661 if (( rt.rt_dist & 0x7f ) + 1 > RTMPHOPS_MAX ) {
662 rtmp->rt_hops = RTMPHOPS_POISON;
664 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
666 if (rtmp_replace( rtmp ) < 0) {
667 syslog(LOG_ERR, "rtmp_packet: rtmp_replace");
671 } else { /* route not in use */
672 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
673 if ( rtmp->rt_hops > ( rt.rt_dist & 0x7f ) + 1 ) {
674 if (rtmp_new( rtmp ) < 0) {
675 syslog(LOG_ERR, "rtmp_packet: rtmp_new");
683 * Make the *next* node the head, since
684 * we're not likely to be asked for the same tuple twice
687 if ( rtmp->rt_next != 0 ) {
688 gate->g_rt->rt_prev->rt_next = gate->g_rt;
689 gate->g_rt = rtmp->rt_next;
692 } else if (( rt.rt_dist & 0x7f ) + 1 > RTMPHOPS_MAX ) {
693 syslog( LOG_INFO, "rtmp_packet bad hop count from %u.%u for %u",
694 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
696 } else { /* new for router */
697 if (( rtmp = newrt(iface)) == NULL ) {
698 syslog( LOG_ERR, "rtmp_packet: newrt: %m" );
701 rtmp->rt_firstnet = rt.rt_net;
702 if ( rt.rt_dist & 0x80 ) {
703 rtmp->rt_lastnet = xrt.rt_net;
704 rtmp->rt_flags = RTMPTAB_EXTENDED;
706 rtmp->rt_lastnet = rt.rt_net;
708 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
709 rtmp->rt_state = RTMPTAB_GOOD;
710 rtmp->rt_gate = gate;
713 * Add rtmptab entry to end of list (leave head alone).
715 if ( gate->g_rt == 0 ) {
716 rtmp->rt_prev = rtmp;
719 rtmp->rt_prev = gate->g_rt->rt_prev;
720 gate->g_rt->rt_prev->rt_next = rtmp;
721 gate->g_rt->rt_prev = rtmp;
724 if (rtmp_new( rtmp ) < 0) {
725 syslog(LOG_ERR, "rtmp_packet: rtmp_new");
730 if ( data + SZ_RTMPTUPLE > end ) {
733 memcpy( &rt, data, SZ_RTMPTUPLE );
734 data += SZ_RTMPTUPLE;
735 if ( rt.rt_dist & 0x80 ) {
736 if ( data + SZ_RTMPTUPLE > end ) {
737 syslog( LOG_INFO, "rtmp_packet missing range-end" );
740 memcpy( &xrt, data, SZ_RTMPTUPLE );
741 data += SZ_RTMPTUPLE;
746 * Make sure we've processed the whole packet.
749 syslog( LOG_INFO, "rtmp_packet length and count mismatch" );
757 if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
758 iface->i_rt->rt_zt == 0 ||
759 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
764 *data++ = DDPTYPE_RTMPRD;
765 rh.rh_net = iface->i_addr.sat_addr.s_net;
767 rh.rh_node = iface->i_addr.sat_addr.s_node;
768 memcpy( data, &rh, sizeof( struct rtmp_head ));
769 data += sizeof( struct rtmp_head );
771 if ( iface->i_flags & IFACE_PHASE2 ) {
772 rt.rt_net = iface->i_rt->rt_firstnet;
774 memcpy( data, &rt, SZ_RTMPTUPLE );
775 data += SZ_RTMPTUPLE;
777 rt.rt_net = iface->i_rt->rt_lastnet;
779 memcpy( data, &rt, SZ_RTMPTUPLE );
780 data += SZ_RTMPTUPLE;
782 if ( sendto( ap->ap_fd, packet, data - packet, 0,
783 (struct sockaddr *)from,
784 sizeof( struct sockaddr_at )) < 0 ) {
785 syslog( LOG_ERR, "as_timer sendto: %m" );
787 } else if ( *data == 2 || *data == 3 ) {
789 printf( "rtmp_packet rdr (%d) from %u.%u\n",
790 *data, ntohs( from->sat_addr.s_net ),
791 from->sat_addr.s_node );
794 syslog( LOG_INFO, "rtmp_packet unknown request from %u.%u\n",
795 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
800 syslog( LOG_INFO, "rtmp_packet bad ddp type from %u.%u",
801 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
808 int rtmp_request( iface )
809 struct interface *iface;
811 struct sockaddr_at sat;
813 char *data, packet[ 2 ];
815 syslog( LOG_INFO, "rtmp_request for %s", iface->i_name );
817 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
818 if ( ap->ap_packet == rtmp_packet ) {
823 syslog( LOG_ERR, "rtmp_request can't find rtmp socket!" );
828 *data++ = DDPTYPE_RTMPR;
829 *data++ = RTMPROP_REQUEST;
832 * There is a problem with the net zero "hint" hack.
834 memset( &sat, 0, sizeof( struct sockaddr_at ));
836 sat.sat_len = sizeof( struct sockaddr_at );
838 sat.sat_family = AF_APPLETALK;
839 sat.sat_addr.s_net = iface->i_addr.sat_addr.s_net;
840 sat.sat_addr.s_node = ATADDR_BCAST;
841 sat.sat_port = ap->ap_port;
842 if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
843 sizeof( struct sockaddr_at )) < 0 ) {
844 syslog( LOG_ERR, "rtmp_request sendto: %m" );
851 int looproute( iface, cmd )
852 struct interface *iface;
855 struct sockaddr_at dst, loop;
857 if ( cmd == RTMP_DEL && ( iface->i_flags & IFACE_LOOP ) == 0 ) {
858 syslog( LOG_ERR, "looproute panic no route" );
862 if ( cmd == RTMP_ADD && ( iface->i_flags & IFACE_LOOP )) {
863 syslog( LOG_ERR, "looproute panic two routes" );
867 memset( &dst, 0, sizeof( struct sockaddr_at ));
869 dst.sat_len = sizeof( struct sockaddr_at );
871 dst.sat_family = AF_APPLETALK;
872 dst.sat_addr.s_net = iface->i_addr.sat_addr.s_net;
873 dst.sat_addr.s_node = iface->i_addr.sat_addr.s_node;
874 memset( &loop, 0, sizeof( struct sockaddr_at ));
876 loop.sat_len = sizeof( struct sockaddr_at );
878 loop.sat_family = AF_APPLETALK;
879 loop.sat_addr.s_net = htons( ATADDR_ANYNET );
880 loop.sat_addr.s_node = ATADDR_ANYNODE;
882 if ( route( cmd, &dst, &loop, RTF_UP | RTF_HOST )) {
885 if ( cmd == RTMP_ADD ) {
886 iface->i_flags |= IFACE_LOOP;
888 if ( cmd == RTMP_DEL ) {
889 iface->i_flags &= ~IFACE_LOOP;
894 int gateroute( command, rtmp )
896 struct rtmptab *rtmp;
898 struct sockaddr_at dst, gate;
901 if ( command == RTMP_DEL && ( rtmp->rt_flags & RTMPTAB_ROUTE ) == 0 ) {
904 if ( command == RTMP_ADD && ( rtmp->rt_flags & RTMPTAB_ROUTE )) {
908 net = ntohs( rtmp->rt_firstnet );
910 * Since we will accept routes from gateways who advertise their
911 * address as 0.YY, we must munge the gateway address we give to
912 * the kernel. Otherwise, we'll get a bunch of routes to the loop
913 * back interface, and who wants that?
915 memset( &gate, 0, sizeof( struct sockaddr_at ));
917 gate.sat_len = sizeof( struct sockaddr_at );
919 gate.sat_family = AF_APPLETALK;
920 gate.sat_addr.s_net = rtmp->rt_gate->g_sat.sat_addr.s_net;
921 gate.sat_addr.s_node = rtmp->rt_gate->g_sat.sat_addr.s_node;
922 if ( gate.sat_addr.s_net == 0 ) {
923 gate.sat_addr.s_net = net;
926 memset( &dst, 0, sizeof( struct sockaddr_at ));
928 dst.sat_len = sizeof( struct sockaddr_at );
930 dst.sat_family = AF_APPLETALK;
931 dst.sat_addr.s_node = ATADDR_ANYNODE;
934 dst.sat_addr.s_net = htons( net );
935 if ( route( command, &dst, &gate, RTF_UP | RTF_GATEWAY )) {
936 syslog( LOG_ERR, "route: %u -> %u.%u: %m", net,
937 ntohs( gate.sat_addr.s_net ), gate.sat_addr.s_node );
940 } while ( net++ < ntohs( rtmp->rt_lastnet ));
942 if ( command == RTMP_ADD ) {
943 rtmp->rt_flags |= RTMPTAB_ROUTE;
945 if ( command == RTMP_DEL ) {
946 rtmp->rt_flags &= ~RTMPTAB_ROUTE;
953 newrt(const struct interface *iface)
955 struct rtmptab *rtmp;
957 if (( rtmp = (struct rtmptab *)calloc(1, sizeof(struct rtmptab))) == 0 ) {
961 rtmp->rt_iface = iface;