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