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