]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/rtmp.c
b227e3a9e9aaaa6c18c1441d794ae08dc0a07ada
[netatalk.git] / etc / atalkd / rtmp.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved. See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdlib.h>
11 #include <string.h>
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>
17 #include <net/if.h>
18 #include <net/route.h>
19 #include <netatalk/endian.h>
20 #include <netatalk/at.h>
21
22 #ifdef __svr4__
23 #include <sys/sockio.h>
24 #endif __svr4__
25
26 #include <atalk/ddp.h>
27 #include <atalk/atp.h>
28 #include <atalk/rtmp.h>
29
30 #include "interface.h"
31 #include "gate.h"
32 #include "rtmp.h"
33 #include "zip.h"
34 #include "list.h"
35 #include "atserv.h"
36 #include "route.h"
37 #include "main.h"
38
39 void rtmp_delzonemap(rtmp)
40     struct rtmptab *rtmp;
41 {
42     struct list         *lz, *flz, *lr, *flr;
43     struct ziptab       *zt;
44
45     lz = rtmp->rt_zt;
46     while ( lz ) {                                      /* for each zone */
47         zt = (struct ziptab *)lz->l_data;
48         lr = zt->zt_rt;
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 ) {
54                             ziptab = zt->zt_next;
55                         } else {
56                             zt->zt_prev->zt_next = zt->zt_next;
57                         }
58                         if ( zt->zt_next == NULL ) {
59                             ziplast = zt->zt_prev;
60                         } else {
61                             zt->zt_next->zt_prev = zt->zt_prev;
62                         }
63                         free( zt->zt_bcast );
64                         free( zt->zt_name );
65                         free( zt );
66                     } else {
67                         zt->zt_rt = lr->l_next;
68                     }
69                 } else {
70                     lr->l_prev->l_next = lr->l_next;
71                 }
72                 if ( lr->l_next != NULL ) {
73                     lr->l_next->l_prev = lr->l_prev;
74                 }
75                 flr = lr;
76                 lr = lr->l_next;
77                 free( flr );
78             } else {
79                 lr = lr->l_next;
80             }
81         }
82         flz = lz;
83         lz = lz->l_next;
84         free( flz );
85     }
86     rtmp->rt_zt = NULL;
87 }
88
89
90 /*
91  * Complete configuration for phase 1 interface using RTMP information.
92  */
93 static int rtmp_config( rh, iface )
94     struct rtmp_head    *rh;
95     struct interface    *iface;
96 {
97     extern int          stabletimer;
98     int cc;
99
100     /*
101      * If we're configuring a phase 2 interface, don't complete
102      * configuration with RTMP.
103      */
104     if ( iface->i_flags & IFACE_PHASE2 ) {
105         syslog( LOG_INFO, "rtmp_config ignoring data" );
106         return 0;
107     }
108
109     /*
110      * Check our seed information, and reconfigure.
111      */
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",
116                     ntohs( rh->rh_net ),
117                     ntohs( iface->i_addr.sat_addr.s_net ));
118             return 1;
119         }
120         iface->i_addr.sat_addr.s_net = rh->rh_net;
121
122         /*
123          * It is possible that we will corrupt our route database
124          * by just forcing this change.  XXX
125          */
126         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = rh->rh_net;
127
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;
131     }
132
133     /* add addr to loopback route */
134     if ((cc = looproute( iface, RTMP_ADD )) < 0 )
135       return -1;
136
137     if (cc) {
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 );
141     }
142
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;
147         bootaddr( ciface );
148     }
149
150     return 0;
151 }
152
153 /*
154  * Delete rtmp from the per-interface in-use table, remove all
155  * zone references, and remove the route from the kernel.
156  */
157 static void rtmp_delinuse( rtmp )
158     struct rtmptab      *rtmp;
159 {
160     struct rtmptab      *irt;
161
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;
166         } else {
167             irt->rt_inext = rtmp->rt_inext;
168             rtmp->rt_inext->rt_iprev = rtmp->rt_iprev;
169         }
170     } else {
171         if ( rtmp->rt_inext == NULL ) {                 /* last */
172             rtmp->rt_iprev->rt_inext = NULL;
173             irt->rt_inext->rt_iprev = rtmp->rt_iprev;
174         } else {
175             rtmp->rt_iprev->rt_inext = rtmp->rt_inext;
176             rtmp->rt_inext->rt_iprev = rtmp->rt_iprev;
177         }
178     }
179     rtmp->rt_iprev = NULL;
180     rtmp->rt_inext = NULL;
181
182     /* remove zone map */
183     rtmp_delzonemap(rtmp);
184
185     /* remove old route */
186     gateroute( RTMP_DEL, rtmp );
187 }
188
189 /*
190  * Add rtmp to the per-interface in-use table.  No verification is done...
191  */
192 static void rtmp_addinuse( rtmp )
193     struct rtmptab      *rtmp;
194 {
195     struct rtmptab      *irt;
196
197     gateroute( RTMP_ADD, rtmp );
198
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;
204     } else {
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;
209     }
210 }
211
212
213 /*
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
218  * an RTMP packet?
219  */
220 static int rtmp_copyzones( to, from )
221     struct rtmptab      *to, *from;
222 {
223     struct list         *lz, *lr;
224
225     to->rt_zt = from->rt_zt;
226     from->rt_zt = NULL;
227     if ( from->rt_flags & RTMPTAB_HASZONES ) {
228         to->rt_flags |= RTMPTAB_HASZONES;
229     }
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 */
234                 break;
235             }
236         }
237         if ( lr == NULL ) {
238             syslog( LOG_ERR, "rtmp_copyzones z -> r without r -> z, abort" );
239             return -1;
240         }
241     }
242
243     return 0;
244 }
245
246
247 /*
248  * Remove rtmp from the in-use table and the per-gate table.
249  * Free any associated space.
250  */
251 void rtmp_free( rtmp )
252     struct rtmptab      *rtmp;
253 {
254     struct gate         *gate;
255
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 );
260     }
261
262     /* remove from per-gate */
263     gate = rtmp->rt_gate;
264     if ( gate->g_rt == rtmp ) {                         /* first */
265         if ( rtmp->rt_prev == rtmp ) {                  /* only */
266             gate->g_rt = NULL;
267         } else {
268             gate->g_rt = rtmp->rt_next;
269             rtmp->rt_next->rt_prev = rtmp->rt_prev;
270         }
271     } else {
272         if ( rtmp->rt_next == NULL ) {                  /* last */
273             rtmp->rt_prev->rt_next = NULL;
274             gate->g_rt->rt_prev = rtmp->rt_prev;
275         } else {
276             rtmp->rt_prev->rt_next = rtmp->rt_next;
277             rtmp->rt_next->rt_prev = rtmp->rt_prev;
278         }
279     }
280
281     free( rtmp );
282 }
283
284
285 /*
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.
288  */
289 int rtmp_replace( replace )
290     struct rtmptab      *replace;
291 {
292     struct interface    *iface;
293     struct gate         *gate;
294     struct rtmptab      *rtmp, *found = NULL;
295
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))
301           continue;
302
303         for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
304             for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
305                 if ( rtmp->rt_firstnet == replace->rt_firstnet &&
306                         rtmp->rt_lastnet == replace->rt_lastnet ) {
307                     if ( found == NULL || rtmp->rt_hops < found->rt_hops ) {
308                         found = rtmp;
309                     }
310                     break;
311                 }
312             }
313         }
314     }
315
316     if ( found != replace ) {
317         if (rtmp_copyzones( found, replace ) < 0)
318           return -1;
319         rtmp_delinuse( replace );
320         rtmp_addinuse( found );
321         if ( replace->rt_state == RTMPTAB_BAD ) {
322             rtmp_free( replace );
323         }
324         return( 0 );
325     } else {
326         if ( replace->rt_hops == RTMPHOPS_POISON ) {
327             gateroute( RTMP_DEL, replace );
328         }
329         return( 1 );
330     }
331 }
332
333
334 static int rtmp_new( rtmp )
335     struct rtmptab      *rtmp;
336 {
337     struct interface    *i;
338     struct rtmptab      *r;
339     extern int          newrtmpdata;
340
341     newrtmpdata = 1;
342
343     /*
344      * Do we already have a gateway for this route?
345      */
346     for ( i = interfaces; i; i = i->i_next ) {
347         if ((rtmp->rt_iface != i) && 
348             ((i->i_flags & IFACE_ISROUTER) == 0))
349           continue;
350
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 ))) {
357                 break;
358             }
359         }
360         if ( r ) {
361             break;
362         }
363     }
364
365     /*
366      * This part of this routine is almost never run.
367      */
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 ));
374             return 1;
375         }
376
377         /*
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.
383          */
384         if ( r->rt_hops < rtmp->rt_hops ) {
385             return 1;
386         }
387
388         if (rtmp_copyzones( rtmp, r ) < 0)
389           return -1;
390         rtmp_delinuse( r );
391     }
392
393     rtmp_addinuse( rtmp );
394     return 0;
395 }
396
397
398 int rtmp_packet( ap, from, data, len )
399     struct atport       *ap;
400     struct sockaddr_at  *from;
401     char                *data;
402     int                 len;
403 {
404     struct rtmp_head    rh;
405     struct rtmp_tuple   rt, xrt;
406     struct gate         *gate;
407     struct interface    *iface;
408     struct rtmptab      *rtmp;
409     char                *end, packet[ ATP_BUFSIZ ];
410     int                 cc;
411
412     end = data + len;
413
414     if ( data >= end ) {
415         syslog( LOG_INFO, "rtmp_packet no data" );
416         return 1;
417     }
418
419     iface = ap->ap_iface;
420
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  ) {
424         return 0;
425     }
426
427     switch( *data++ ) {
428     case DDPTYPE_RTMPRD :
429         /*
430          * Response and Data.
431          */
432         if ( data + sizeof( struct rtmprdhdr ) > end ) {
433             syslog( LOG_INFO, "rtmp_packet no data header" );
434             return 1;
435         }
436         memcpy( &rh, data, sizeof( struct rtmprdhdr ));
437         data += sizeof( struct rtmprdhdr );
438
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 );
442             return 1;
443         }
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" );
448             return 1;
449         }
450
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");
456                   return -1;
457                 } 
458
459                 if (cc)
460                   syslog( LOG_ERR, "rtmp_packet: can't remove loopback: %m" );
461
462                 iface->i_flags &= ~IFACE_NOROUTER;
463                 iface->i_time = 0;
464                 syslog( LOG_INFO, "rtmp_packet router has become available" );
465             }
466             if ( iface->i_flags & IFACE_PHASE1 ) {
467               if (rtmp_config( &rh, iface ) < 0) {
468                   syslog(LOG_ERR, "rtmp_packet: rtmp_config");
469                   return -1;
470               }
471             } else if (zip_getnetinfo( iface ) < 0) {
472               syslog(LOG_ERR, "rtmp_packet: zip_getnetinfo");
473               return -1;
474             }
475             return 0;
476         }
477
478         if (( iface->i_flags & IFACE_CONFIG ) == 0 ) {
479             return 0;
480         }
481
482         /*
483          * Parse first tuple.  For phase 2, verify that net is correct.
484          */
485         if ( data + SZ_RTMPTUPLE > end ) {
486             syslog( LOG_INFO, "rtmp_packet missing first tuple" );
487             return 1;
488         }
489         memcpy( &rt, data, SZ_RTMPTUPLE );
490         data += SZ_RTMPTUPLE;
491
492         if ( rt.rt_net == 0 ) {
493             if ( rt.rt_dist != 0x82 ) {
494                 syslog( LOG_INFO, "rtmp_packet bad phase 1 version" );
495                 return 1;
496             }
497
498             /*
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.
502              */
503             if ( data + SZ_RTMPTUPLE > end ) {
504                 syslog( LOG_INFO, "rtmp_packet missing second tuple" );
505                 return 1;
506             }
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" );
512                 return 1;
513             }
514             memcpy( &xrt, data, SZ_RTMPTUPLE );
515             data += SZ_RTMPTUPLE;
516
517             if ( xrt.rt_dist != 0x82 ) {
518                 syslog( LOG_INFO, "rtmp_packet bad phase 2 version" );
519                 return 1;
520             }
521
522             /*
523              * Check for net range conflict.
524              */
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" );
528                 return 1;
529             }
530         } else {
531 #ifdef PHASE1NET
532             /*
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" );
539                 return 1;
540             }
541              */
542 #else PHASE1NET
543             syslog( LOG_INFO, "rtmp_packet bad first tuple" );
544             return 1;
545 #endif PHASE1NET
546         }
547
548         /*
549          * Find gateway.
550          */
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 ) {
554                 break;
555             }
556         }
557         if ( !gate ) {  /* new gateway */
558             if (( gate = (struct gate *)malloc( sizeof( struct gate ))) == 0 ) {
559                 syslog( LOG_ERR, "rtmp_packet: malloc: %m" );
560                 return -1;
561             }
562             gate->g_next = iface->i_gate;
563             gate->g_prev = 0;
564             gate->g_rt = 0;
565             gate->g_iface = iface;      /* need this? */
566             gate->g_sat = *from;
567             if ( iface->i_gate ) {
568                 iface->i_gate->g_prev = gate;
569             }
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 );
574         }
575
576         /*
577          * Reset the timeout on this gateway.  We'll remove the gateway
578          * entry, if the timeout gets to RTMPTAB_BAD.
579          */
580         gate->g_state = RTMPTAB_GOOD;
581
582         /*
583          * Parse remaining tuples.
584          */
585         for (;;) {
586             /*
587              * Is route on this gateway?
588              */
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 )) {
592                     break;
593                 }
594                 if (( rt.rt_dist & 0x80 ) &&
595                         ntohs( rtmp->rt_firstnet ) <= ntohs( xrt.rt_net ) &&
596                         ntohs( rtmp->rt_lastnet ) >= ntohs( xrt.rt_net )) {
597                     break;
598                 }
599             }
600
601             if ( rtmp ) {       /* found it */
602                 /*
603                  * Check for range conflicts.  (This is getting a little
604                  * ugly.)
605                  */
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 ));
609                     return 1;
610                 }
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 ));
615                         return 1;
616                     }
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 ));
620                         return 1;
621                     }
622                 } else {
623                     if ( rtmp->rt_flags & RTMPTAB_EXTENDED ) {
624                         syslog( LOG_INFO, "rtmp_packet !extended mismatch %u",
625                                 ntohs( rtmp->rt_firstnet ));
626                         return 1;
627                     }
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 ));
631                         return 1;
632                     }
633                 }
634
635                 rtmp->rt_state = RTMPTAB_GOOD;
636
637                 /*
638                  * Check hop count.  If the count has changed, update
639                  * the routing database.
640                  */
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 ) {
646                             /*
647                              * If this was POISON, we've deleted it from
648                              * the kernel.  Add it back in.
649                              */
650                             if ( rtmp->rt_hops == RTMPHOPS_POISON ) {
651                                 gateroute( RTMP_ADD, rtmp );
652                             }
653                             rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
654                         } else {
655                             /*
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().
660                              */
661                             if (( rt.rt_dist & 0x7f ) + 1 > RTMPHOPS_MAX ) {
662                                 rtmp->rt_hops = RTMPHOPS_POISON;
663                             } else {
664                                 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
665                             }
666                             if (rtmp_replace( rtmp ) < 0) {
667                               syslog(LOG_ERR, "rtmp_packet: rtmp_replace");
668                               return -1;
669                             }
670                         }
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");
676                               return -1;
677                           }
678                         }
679                     }
680                 }
681
682                 /*
683                  * Make the *next* node the head, since
684                  * we're not likely to be asked for the same tuple twice
685                  * in a row.
686                  */
687                 if ( rtmp->rt_next != 0 ) {
688                     gate->g_rt->rt_prev->rt_next = gate->g_rt;
689                     gate->g_rt = rtmp->rt_next;
690                     rtmp->rt_next = 0;
691                 }
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,
695                         ntohs( rt.rt_net ));
696             } else {            /* new for router */
697                 if (( rtmp = newrt(iface)) == NULL ) {
698                     syslog( LOG_ERR, "rtmp_packet: newrt: %m" );
699                     return -1;
700                 }
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;
705                 } else {
706                     rtmp->rt_lastnet = rt.rt_net;
707                 }
708                 rtmp->rt_hops = ( rt.rt_dist & 0x7f ) + 1;
709                 rtmp->rt_state = RTMPTAB_GOOD;
710                 rtmp->rt_gate = gate;
711
712                 /*
713                  * Add rtmptab entry to end of list (leave head alone).
714                  */
715                 if ( gate->g_rt == 0 ) {
716                     rtmp->rt_prev = rtmp;
717                     gate->g_rt = rtmp;
718                 } else {
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;
722                 }
723                 
724                 if (rtmp_new( rtmp ) < 0) {
725                     syslog(LOG_ERR, "rtmp_packet: rtmp_new");
726                     return -1;
727                 }
728             }
729
730             if ( data + SZ_RTMPTUPLE > end ) {
731                 break;
732             }
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" );
738                     return 1;
739                 }
740                 memcpy( &xrt, data, SZ_RTMPTUPLE );
741                 data += SZ_RTMPTUPLE;
742             }
743         }
744
745         /*
746          * Make sure we've processed the whole packet.
747          */
748         if ( data != end ) {
749             syslog( LOG_INFO, "rtmp_packet length and count mismatch" );
750         }
751         break;
752
753     case DDPTYPE_RTMPR :
754         /*
755          * Request and RDR.
756          */
757         if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
758             iface->i_rt->rt_zt == 0 ||
759             ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
760             return 0;
761         }
762         if ( *data == 1 ) {
763             data = packet;
764             *data++ = DDPTYPE_RTMPRD;
765             rh.rh_net = iface->i_addr.sat_addr.s_net;
766             rh.rh_nodelen = 8;
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 );
770
771             if ( iface->i_flags & IFACE_PHASE2 ) {
772                 rt.rt_net = iface->i_rt->rt_firstnet;
773                 rt.rt_dist = 0x80;
774                 memcpy( data, &rt, SZ_RTMPTUPLE );
775                 data += SZ_RTMPTUPLE;
776
777                 rt.rt_net = iface->i_rt->rt_lastnet;
778                 rt.rt_dist = 0x82;
779                 memcpy( data, &rt, SZ_RTMPTUPLE );
780                 data += SZ_RTMPTUPLE;
781             }
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" );
786             }
787         } else if ( *data == 2 || *data == 3 ) {
788 #ifdef DEBUG
789             printf( "rtmp_packet rdr (%d) from %u.%u\n",
790                     *data, ntohs( from->sat_addr.s_net ),
791                     from->sat_addr.s_node );
792 #endif DEBUG
793         } else {
794             syslog( LOG_INFO, "rtmp_packet unknown request from %u.%u\n",
795                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
796         }
797         break;
798
799     default :
800         syslog( LOG_INFO, "rtmp_packet bad ddp type from %u.%u",
801                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
802         return 0;
803     }
804
805     return 0;
806 }
807
808 int rtmp_request( iface )
809     struct interface    *iface;
810 {
811     struct sockaddr_at  sat;
812     struct atport       *ap;
813     char                *data, packet[ 2 ];
814
815     syslog( LOG_INFO, "rtmp_request for %s", iface->i_name );
816
817     for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
818         if ( ap->ap_packet == rtmp_packet ) {
819             break;
820         }
821     }
822     if ( ap == 0 ) {
823         syslog( LOG_ERR, "rtmp_request can't find rtmp socket!" );
824         return -1;
825     }
826
827     data = packet;
828     *data++ = DDPTYPE_RTMPR;
829     *data++ = RTMPROP_REQUEST;
830
831     /*
832      * There is a problem with the net zero "hint" hack.
833      */
834     memset( &sat, 0, sizeof( struct sockaddr_at ));
835 #ifdef BSD4_4
836     sat.sat_len = sizeof( struct sockaddr_at );
837 #endif BSD4_4
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" );
845         return -1;
846     }
847     return 0;
848 }
849
850
851 int looproute( iface, cmd )
852     struct interface    *iface;
853     int                 cmd;
854 {
855     struct sockaddr_at  dst, loop;
856
857     if ( cmd == RTMP_DEL && ( iface->i_flags & IFACE_LOOP ) == 0 ) {
858         syslog( LOG_ERR, "looproute panic no route" );
859         return -1;
860     }
861
862     if ( cmd == RTMP_ADD && ( iface->i_flags & IFACE_LOOP )) {
863         syslog( LOG_ERR, "looproute panic two routes" );
864         return -1;
865     }
866
867     memset( &dst, 0, sizeof( struct sockaddr_at ));
868 #ifdef BSD4_4
869     dst.sat_len = sizeof( struct sockaddr_at );
870 #endif BSD4_4
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 ));
875 #ifdef BSD4_4
876     loop.sat_len = sizeof( struct sockaddr_at );
877 #endif BSD4_4
878     loop.sat_family = AF_APPLETALK;
879     loop.sat_addr.s_net = htons( ATADDR_ANYNET );
880     loop.sat_addr.s_node = ATADDR_ANYNODE;
881
882     if ( route( cmd, &dst, &loop, RTF_UP | RTF_HOST )) {
883         return( 1 );
884     }
885     if ( cmd == RTMP_ADD ) {
886         iface->i_flags |= IFACE_LOOP;
887     }
888     if ( cmd == RTMP_DEL ) {
889         iface->i_flags &= ~IFACE_LOOP;
890     }
891     return( 0 );
892 }
893
894 int gateroute( command, rtmp )
895     int                 command;
896     struct rtmptab      *rtmp;
897 {
898     struct sockaddr_at  dst, gate;
899     unsigned short      net;
900
901     if ( command == RTMP_DEL && ( rtmp->rt_flags & RTMPTAB_ROUTE ) == 0 ) {
902         return( -1 );
903     }
904     if ( command == RTMP_ADD && ( rtmp->rt_flags & RTMPTAB_ROUTE )) {
905         return( -1 );
906     }
907
908     net = ntohs( rtmp->rt_firstnet );
909     /*
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?
914      */
915     memset( &gate, 0, sizeof( struct sockaddr_at ));
916 #ifdef BSD4_4
917     gate.sat_len = sizeof( struct sockaddr_at );
918 #endif BSD4_4
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;
924     }
925
926     memset( &dst, 0, sizeof( struct sockaddr_at ));
927 #ifdef BSD4_4
928     dst.sat_len = sizeof( struct sockaddr_at );
929 #endif BSD4_4
930     dst.sat_family = AF_APPLETALK;
931     dst.sat_addr.s_node = ATADDR_ANYNODE;
932
933     do {
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 );
938             continue;
939         }
940     } while ( net++ < ntohs( rtmp->rt_lastnet ));
941
942     if ( command == RTMP_ADD ) {
943         rtmp->rt_flags |= RTMPTAB_ROUTE;
944     }
945     if ( command == RTMP_DEL ) {
946         rtmp->rt_flags &= ~RTMPTAB_ROUTE;
947     }
948
949     return( 0 );
950 }
951
952     struct rtmptab *
953 newrt(const struct interface *iface)
954 {
955     struct rtmptab      *rtmp;
956
957     if (( rtmp = (struct rtmptab *)calloc(1, sizeof(struct rtmptab))) == 0 ) {
958         return( 0 );
959     }
960
961     rtmp->rt_iface = iface;
962     return( rtmp );
963 }