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