~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to etc/atalkd/rtmp.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

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