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