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