]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/zip.c
CVS id tags, define fixes, code beautification
[netatalk.git] / etc / atalkd / zip.c
1 /*
2  * $Id: zip.c,v 1.6 2001-06-25 20:13:45 rufustfirefly 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 <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/syslog.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
19 #include <sys/time.h>
20 #include <net/if.h>
21 #include <net/route.h>
22 #include <netatalk/endian.h>
23 #include <netatalk/at.h>
24
25 #ifdef __svr4__
26 #include <sys/sockio.h>
27 #endif /* __svr4__ */
28
29 #include <atalk/ddp.h>
30 #include <atalk/zip.h>
31 #include <atalk/atp.h>
32 #include <atalk/util.h>
33
34 #include "atserv.h"
35 #include "interface.h"
36 #include "gate.h"
37 #include "zip.h"
38 #include "rtmp.h"
39 #include "list.h"
40 #include "multicast.h"
41 #include "main.h"
42
43 struct ziptab   *ziptab = NULL, *ziplast = NULL;
44
45
46 static int zonecheck( rtmp, iface )
47     struct rtmptab      *rtmp;
48     struct interface    *iface;
49 {
50     struct list         *l;
51     struct ziptab       *czt, *zt;
52     int                 cztcnt, ztcnt;
53
54     if (( iface->i_flags & IFACE_SEED ) == 0 ) {
55         return( 0 );
56     }
57
58     for ( cztcnt = 0, czt = iface->i_czt; czt; czt = czt->zt_next, cztcnt++ ) {
59         for ( l = rtmp->rt_zt; l; l = l->l_next ) {
60             zt = (struct ziptab *)l->l_data;
61             if ( czt->zt_len == zt->zt_len &&
62                     !strndiacasecmp( czt->zt_name, zt->zt_name, czt->zt_len )) {
63                 break;
64             }
65         }
66         if ( l == 0 ) {
67             syslog( LOG_ERR, "zonecheck: %.*s not in zone list", czt->zt_len,
68                     czt->zt_name );
69             return( -1 );       /* configured zone not found in net zones */
70         }
71     }
72
73     for ( ztcnt = 0, l = rtmp->rt_zt; l; l = l->l_next, ztcnt++ )
74         ;
75
76     if ( cztcnt != ztcnt ) {
77         syslog( LOG_ERR, "zonecheck: %d configured zones, %d zones found",
78                 cztcnt, ztcnt );
79         return( -1 );           /* more net zones than configured zones */
80     }
81
82     return( 0 );
83 }
84
85
86 int zip_packet( ap, from, data, len )
87     struct atport       *ap;
88     struct sockaddr_at  *from;
89     char                *data;
90     int                 len;
91 {
92     struct ziphdr       zh;
93     struct atphdr       ah;
94     struct interface    *iface;
95     struct gate         *gate;
96     struct rtmptab      *rtmp;
97     struct list         *l;
98     struct ziptab       *zt;
99     u_short             firstnet, lastnet, index, nz;
100     char                *end, zname[ 32 ], packet[ ATP_BUFSIZ ], *nzones, *lastflag;
101     char                *reply, *rend, *ziphdr;
102     int                 zlen, n, zipop, rcnt, qcnt, zcnt, zsz;
103     extern int          stabletimer;
104
105     end = data + len;
106
107     if ( data >= end ) {
108         syslog( LOG_INFO, "zip_packet malformed packet" );
109         return 1;
110     }
111
112     /* get interface */
113     iface = ap->ap_iface;
114
115     switch( *data++ ) {
116     case DDPTYPE_ZIP :
117         if ( data + sizeof( struct ziphdr ) > end ) {
118             syslog( LOG_INFO, "zip_packet malformed packet" );
119             return 1;
120         }
121         memcpy( &zh, data, sizeof( struct ziphdr ));
122         data += sizeof( struct ziphdr );
123
124         switch ( zh.zh_op ) {
125         case ZIPOP_QUERY :
126             /* set up reply */
127             reply = packet;
128             rend = packet + sizeof( packet );
129             *reply++ = DDPTYPE_ZIP;
130             ziphdr = reply;
131             reply += 2;
132             rcnt = 0;
133
134             qcnt = zh.zh_count;
135
136             while ( data + sizeof( u_short ) <= end && qcnt-- > 0 ) {
137                 memcpy( &firstnet, data, sizeof( u_short ));
138                 data += sizeof( u_short );
139
140                 /*
141                  * Look for the given network number (firstnet).
142                  * Perhaps we could do better than brute force?
143                  */
144                 for ( iface = interfaces; iface; iface = iface->i_next ) {
145                     for ( rtmp = iface->i_rt; rtmp; rtmp = rtmp->rt_inext ) {
146                         if ( firstnet == rtmp->rt_firstnet ) {
147                             break;
148                         }
149                     }
150                     if ( rtmp ) {
151                         break;
152                     }
153                 }
154                 if ( rtmp == 0 ) {
155                     continue;
156                 }
157
158                 /*
159                  * Count the number of zones in this list, and the
160                  * number of byte it will consume in a reply.
161                  */
162                 for ( zsz = 0, zcnt = 0, l = rtmp->rt_zt; l; l = l->l_next ) {
163                     zcnt++;
164                     zt = (struct ziptab *)l->l_data;
165                     zsz += sizeof( u_short ) + 1 + zt->zt_len;
166                 }
167
168                 /*
169                  * We might send this list in the current reply, as the
170                  * first thing in the next reply, or as an extended packet.
171                  */
172                 if ( reply + zsz > rend ) {
173                     if ( rcnt > 0 ) {
174                         zh.zh_op = ZIPOP_REPLY;
175                         zh.zh_cnt = rcnt;
176                         memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
177                         if ( sendto( ap->ap_fd, packet, reply - packet, 0,
178                                 (struct sockaddr *)from,
179                                 sizeof( struct sockaddr_at )) < 0 ) {
180                             syslog( LOG_ERR, "zip reply sendto: %m" );
181                         }
182
183                         reply = packet + 3;
184                         rcnt = 0;
185                     }
186
187                     if ( reply + zsz > rend ) {
188                         /* ereply */
189                         for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
190                             zt = (struct ziptab *)l->l_data;
191                             if ( reply + sizeof( u_short ) + 1 + zt->zt_len >
192                                     rend ) {
193                                 zh.zh_op = ZIPOP_EREPLY;
194                                 zh.zh_cnt = zcnt;
195                                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
196                                 if ( sendto( ap->ap_fd, packet, reply - packet,
197                                         0, (struct sockaddr *)from,
198                                         sizeof( struct sockaddr_at )) < 0 ) {
199                                     syslog( LOG_ERR, "zip reply sendto: %m" );
200                                 }
201
202                                 reply = packet + 3;
203                                 rcnt = 0;
204                             }
205
206                             memcpy( reply, &firstnet, sizeof( u_short ));
207                             reply += sizeof( u_short );
208                             *reply++ = zt->zt_len;
209                             memcpy( reply, zt->zt_name, zt->zt_len );
210                             reply += zt->zt_len;
211                         }
212
213                         if ( rcnt > 0 ) {
214                             zh.zh_op = ZIPOP_EREPLY;
215                             zh.zh_cnt = zcnt;
216                             memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
217                             if ( sendto( ap->ap_fd, packet, reply - packet, 0,
218                                     (struct sockaddr *)from,
219                                     sizeof( struct sockaddr_at )) < 0 ) {
220                                 syslog( LOG_ERR, "zip reply sendto: %m" );
221                             }
222
223                             reply = packet + 3;
224                             rcnt = 0;
225                         }
226                         continue;
227                     }
228                 }
229
230                 for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
231                     zt = (struct ziptab *)l->l_data;
232                     memcpy( reply, &firstnet, sizeof( u_short ));
233                     reply += sizeof( u_short );
234                     *reply++ = zt->zt_len;
235                     memcpy( reply, zt->zt_name, zt->zt_len );
236                     reply += zt->zt_len;
237                 }
238             }
239
240             if ( rcnt > 0 ) {
241                 zh.zh_op = ZIPOP_REPLY;
242                 zh.zh_cnt = rcnt;
243                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
244                 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
245                         (struct sockaddr *)from,
246                         sizeof( struct sockaddr_at )) < 0 ) {
247                     syslog( LOG_ERR, "zip reply sendto: %m" );
248                 }
249             }
250             break;
251
252         case ZIPOP_REPLY :
253             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
254                 if (( from->sat_addr.s_net == 0 ||
255                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
256                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
257                     break;
258                 }
259             }
260             if ( gate == NULL ) {
261                 syslog( LOG_INFO, "zip reply from non-gateway %u.%u", 
262                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
263                 return 1;
264             }
265
266             rtmp = NULL;
267
268             do {
269                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
270                     syslog( LOG_INFO, "zip reply short (%d)", len );
271                     return 1;
272                 }
273                 memcpy( &firstnet, data, sizeof( u_short ));
274                 data += sizeof( u_short );
275
276                 if ( rtmp && rtmp->rt_firstnet != firstnet ) {
277                     /* XXX */
278                     if ( rtmp->rt_gate == NULL &&
279                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
280                         syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
281                         return -1;
282                     }
283                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
284                 }
285
286                 /* Check if this is the interface's route. */
287                 if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
288                     rtmp = gate->g_iface->i_rt;
289                 } else {
290                     for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
291                         if ( rtmp->rt_firstnet == firstnet ) {
292                             break;
293                         }
294                     }
295
296                     /*
297                      * Update head to this rtmp entry.
298                      */
299                     if ( rtmp != 0 && gate->g_rt != rtmp ) {
300                         gate->g_rt->rt_prev->rt_next = gate->g_rt;
301                         gate->g_rt = rtmp;
302                         rtmp->rt_prev->rt_next = 0;
303                     }
304                 }
305
306                 zlen = *data++;
307                 if ( zlen > 32 || zlen <= 0 ) {
308                     syslog( LOG_INFO, "zip reply bad packet" );
309                     return 1;
310                 }
311                 if ( data + zlen > end ) {
312                     syslog( LOG_INFO, "zip reply short (%d)", len );
313                     return 1;
314                 }
315                 memcpy( zname, data, zlen );
316                 data += zlen;
317
318                 /*
319                  * We won't find any rtmp entry if the gateway is no longer
320                  * telling us about the entry.
321                  */
322                 if ( rtmp == 0 ) {
323                     syslog( LOG_INFO, "zip skip reply %u from %u.%u (no rtmp)",
324                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
325                             from->sat_addr.s_node );
326                 /*
327                  * Check if the route is still in use (the iprev check is
328                  * no good if rtmp is the interface's route).
329                  */
330                 } else if ( rtmp->rt_iprev == NULL && rtmp->rt_prev != NULL ) {
331                     syslog( LOG_INFO,
332                             "zip skip reply %u-%u from %u.%u (rtmp not in use)",
333                             ntohs( rtmp->rt_firstnet ),
334                             ntohs( rtmp->rt_lastnet ),
335                             ntohs( from->sat_addr.s_net ),
336                             from->sat_addr.s_node );
337                 /*
338                  * Check if we've got an outstanding query for this route.
339                  * We will often get this, since we ask every router on a
340                  * net to verify our interface's zone(s).
341                  */
342                 } else if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
343                     syslog( LOG_INFO,
344                             "zip skip reply %u-%u from %u.%u (no query)",
345                             ntohs( rtmp->rt_firstnet ),
346                             ntohs( rtmp->rt_lastnet ),
347                             ntohs( from->sat_addr.s_net ),
348                             from->sat_addr.s_node );
349                 } else {
350                     if (addzone( rtmp, zlen, zname ) < 0) {
351                         syslog(LOG_ERR, "zip_packet: addzone");
352                         return -1;
353                     }
354                     rtmp->rt_flags |= RTMPTAB_HASZONES;
355                 }
356             } while ( data < end );
357
358             if ( rtmp && rtmp->rt_flags & RTMPTAB_HASZONES ) {
359                 /* XXX */
360                 if ( rtmp->rt_gate == 0 &&
361                         zonecheck( rtmp, gate->g_iface ) != 0 ) {
362                     syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
363                     return -1;
364                 }
365                 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
366             }
367             break;
368
369         case ZIPOP_EREPLY :
370             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
371                 if (( from->sat_addr.s_net == 0 ||
372                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
373                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
374                     break;
375                 }
376             }
377             if ( gate == NULL ) {
378                 syslog( LOG_INFO, "zip ereply from non-gateway %u.%u", 
379                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
380                 return 1;
381             }
382
383             /*
384              * Note that we're not advancing "data" here.  We do that
385              * at the top of the do-while loop, below.
386              */
387             if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
388                 syslog( LOG_INFO, "zip ereply short (%d)", len );
389                 return 1;
390             }
391             memcpy( &firstnet, data, sizeof( u_short ));
392
393             /* Check if this is the interface's route. */
394             if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
395                 rtmp = gate->g_iface->i_rt;
396             } else {
397                 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
398                     if ( rtmp->rt_firstnet == firstnet ) {
399                         break;
400                     }
401                 }
402                 if ( rtmp == NULL ) {
403                     syslog( LOG_INFO, "zip ereply %u from %u.%u (no rtmp)",
404                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
405                             from->sat_addr.s_node );
406                     return 1;
407                 }
408                 if ( rtmp->rt_iprev == 0 ) {
409                     syslog( LOG_INFO,
410                             "zip ereply %u-%u from %u.%u (rtmp not in use)",
411                             ntohs( rtmp->rt_firstnet ),
412                             ntohs( rtmp->rt_lastnet ),
413                             ntohs( from->sat_addr.s_net ),
414                             from->sat_addr.s_node );
415                 }
416
417                 /* update head to *next* rtmp entry */
418                 if ( rtmp->rt_next != 0 ) {
419                     gate->g_rt->rt_prev->rt_next = gate->g_rt;
420                     gate->g_rt = rtmp->rt_next;
421                     rtmp->rt_next = 0;
422                 }
423             }
424
425             if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
426                 syslog( LOG_INFO, "zip ereply %u-%u from %u.%u (no query)",
427                         ntohs( rtmp->rt_firstnet ),
428                         ntohs( rtmp->rt_lastnet ),
429                         ntohs( from->sat_addr.s_net ),
430                         from->sat_addr.s_node );
431                 return 0;
432             }
433
434             do {
435                 /*
436                  * We copy out firstnet, twice (see above).  Not
437                  * a big deal, and it makes the end condition cleaner.
438                  */
439                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
440                     syslog( LOG_INFO, "zip ereply short (%d)", len );
441                     return 1;
442                 }
443                 memcpy( &firstnet, data, sizeof( u_short ));
444                 data += sizeof( u_short );
445
446                 /* check route */
447                 if ( firstnet != rtmp->rt_firstnet ) {
448                     syslog( LOG_INFO, "zip ereply with multiple nets" );
449                     return 1;
450                 }
451
452                 zlen = *data++;
453                 if ( zlen > 32 || zlen <= 0 ) {
454                     syslog( LOG_INFO, "zip ereply bad zone length (%d)", zlen );
455                     return 1;
456                 }
457                 if ( data + zlen > end ) {
458                     syslog( LOG_INFO, "zip ereply short (%d)", len );
459                     return 1;
460                 }
461                 memcpy( zname, data, zlen );
462                 data += zlen;
463                 if (addzone( rtmp, zlen, zname ) < 0) {
464                     syslog(LOG_ERR, "zip_packet: addzone");
465                     return -1;
466                 }
467             } while ( data < end );
468
469             if ( rtmp ) {
470                 /*
471                  * Count zones for rtmptab entry.
472                  */
473                 for ( n = 0, l = rtmp->rt_zt; l; l = l->l_next, n++ )
474                     ;
475                 if ( n == zh.zh_count ) {
476                     rtmp->rt_flags |= RTMPTAB_HASZONES;
477                     /* XXX */
478                     if ( rtmp->rt_gate == 0 &&
479                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
480                         syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
481                         return -1;
482                     }
483                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
484                 }
485             }
486             break;
487
488         case ZIPOP_GNI :
489             /*
490              * Don't answer with bogus information.
491              */
492             if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
493                 iface->i_rt->rt_zt == 0 ||
494                 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
495                 return 0;
496             }
497
498             if ( zh.zh_zero != 0 || data + 2 * sizeof( u_short ) > end ) {
499                 syslog( LOG_INFO, "zip_packet malformed packet" );
500                 return 1;
501             }
502
503             memcpy( &firstnet, data, sizeof( u_short ));
504             data += sizeof( u_short );
505             memcpy( &lastnet, data, sizeof( u_short ));
506             data += sizeof( u_short );
507             if ( firstnet != 0 || lastnet != 0 || data >= end ) {
508                 syslog( LOG_INFO, "zip_packet malformed packet" );
509                 return 1;
510             }
511
512             zlen = *data++;
513             if ( zlen < 0 || zlen > 32 ) {
514                 syslog( LOG_INFO, "zip_packet malformed packet" );
515                 return 1;
516             }
517             memcpy( zname, data, zlen );
518
519             data = packet;
520             end = data + sizeof( packet );
521             zh.zh_op = ZIPOP_GNIREPLY;
522             zh.zh_flags = 0;
523
524             /*
525              * Skip to the nets.  Fill in header when we're done.
526              */
527             data += 1 + sizeof( struct ziphdr );
528             memcpy( data, &iface->i_rt->rt_firstnet, sizeof( u_short ));
529             data += sizeof( u_short );
530             memcpy( data, &iface->i_rt->rt_lastnet, sizeof( u_short ));
531             data += sizeof( u_short );
532
533             *data++ = zlen;
534             memcpy( data, zname, zlen );
535             data += zlen;
536
537             /*
538              * Check if the given zone is valid.  If it's valid, just fill in
539              * the multicast address.  If it's not, fill the multicast address
540              * in with the default zone and return the default zone.
541              */
542             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
543                 zt = (struct ziptab *)l->l_data;
544                 if ( zt->zt_len == zlen &&
545                         strndiacasecmp( zname, zt->zt_name, zlen ) == 0 ) {
546                     break;
547                 }
548             }
549             if ( l == 0 ) {
550                 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
551                 zh.zh_flags |= ZIPGNI_INVALID;
552             }
553
554             for ( n = 0, l = iface->i_rt->rt_zt; l; l = l->l_next, n++ )
555                 ;
556             if ( n == 1 ) {
557                 zh.zh_flags |= ZIPGNI_ONEZONE;
558             }
559
560             /* multicast */
561             *data++ = 6;        /* sizeof ??? */
562             if (zone_bcast(zt) < 0) {
563               syslog(LOG_ERR, "zip_packet: zone_bcast");
564               return -1;
565             }
566             memcpy(data, zt->zt_bcast, 6);
567             data += 6;
568
569             /*
570              * Add default zone.
571              */
572             if ( zh.zh_flags & ZIPGNI_INVALID ) {
573                 *data++ = zt->zt_len;
574                 memcpy( data, zt->zt_name, zt->zt_len );
575                 data += zt->zt_len;
576             }
577
578             /* fill in header */
579             *packet = DDPTYPE_ZIP;
580             memcpy( packet + 1, &zh, sizeof( struct ziphdr ));
581
582             /*
583              * If the address we received this request from isn't correct
584              * for the net we received it on, send a broadcast.
585              */
586             if ( ntohs( from->sat_addr.s_net ) <
587                     ntohs( iface->i_rt->rt_firstnet ) ||
588                     ntohs( from->sat_addr.s_net ) >
589                     ntohs( iface->i_rt->rt_lastnet )) {
590                 from->sat_addr.s_net = 0;
591                 from->sat_addr.s_node = ATADDR_BCAST;
592             }
593
594             if ( sendto( ap->ap_fd, packet, data - packet, 0,
595                     (struct sockaddr *)from,
596                     sizeof( struct sockaddr_at )) < 0 ) {
597                 syslog( LOG_ERR, "zip gni sendto %u.%u: %m",
598                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
599                 return 1;
600             }
601             break;
602
603         case ZIPOP_GNIREPLY :
604             /*
605              * Ignore ZIP GNIReplys which are either late or unsolicited.
606              */
607             syslog( LOG_DEBUG, "zip gnireply from %u.%u (%s %x)",
608                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
609                     iface->i_name, iface->i_flags );
610
611             if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) ||
612                     ( iface->i_flags & IFACE_ADDR ) == 0 ) {
613                 syslog( LOG_DEBUG, "zip ignoring gnireply" );
614                 return 1;
615             }
616
617             if ( data + 2 * sizeof( u_short ) > end ) {
618                 syslog( LOG_INFO, "zip_packet malformed packet" );
619                 return 1;
620             }
621             memcpy( &firstnet, data, sizeof( u_short ));
622             data += sizeof( u_short );
623             memcpy( &lastnet, data, sizeof( u_short ));
624             data += sizeof( u_short );
625
626             /*
627              * We never ask for a zone, so we can get back what the
628              * default zone is.
629              */
630             if ( data >= end || data + *data > end ) {
631                 syslog( LOG_INFO, "zip_packet malformed packet" );
632                 return 1;
633             }
634             if ( *data++ != 0 ) {
635                 syslog( LOG_INFO, "zip_packet unsolicited zone" );
636                 return 1;
637             }
638
639             /* skip multicast (should really check it) */
640             if ( data >= end || data + *data > end ) {
641                 syslog( LOG_INFO, "zip_packet malformed packet" );
642                 return 1;
643             }
644             data += *data + 1;
645
646             if ( data >= end || data + *data > end ) {
647                 syslog( LOG_INFO, "zip_packet malformed packet" );
648                 return 1;
649             }
650
651             /*
652              * First, if we're not seed, we always get our zone information
653              * from the net -- we don't even save what was in the file.
654              * Second, if we are seed, we keep our zone list in the
655              * interface structure, not in the zone table.  This allows us
656              * to check that the net is giving us good zones.
657              */
658             if ( iface->i_flags & IFACE_SEED ) {
659                 if ( iface->i_czt->zt_len != *data ||
660                         strndiacasecmp( iface->i_czt->zt_name,
661                         data + 1, *data ) != 0 ) {
662                     syslog( LOG_ERR, "default zone mismatch on %s",
663                             iface->i_name );
664                     syslog( LOG_ERR, "%.*s != %.*s",
665                             iface->i_czt->zt_len, iface->i_czt->zt_name,
666                             *data, data + 1 );
667                     syslog( LOG_ERR, "Seed error! Exiting!" );
668                     return -1;
669                 }
670             }
671
672             if (addzone( iface->i_rt, *data, data + 1 ) < 0) {
673                 syslog(LOG_ERR, "zip_packet: addzone");
674                 return -1;
675             }
676             
677             /*
678              * The netrange we received from the router doesn't match the
679              * range we have locally. This is not a problem, unless we
680              * have seed information.
681              */
682             if ( firstnet != iface->i_rt->rt_firstnet ||
683                     lastnet != iface->i_rt->rt_lastnet ) {
684                 if ( iface->i_flags & IFACE_SEED ) {
685                     syslog( LOG_ERR, "netrange mismatch on %s",
686                             iface->i_name );
687                     syslog( LOG_ERR, "%u-%u != %u-%u",
688                             ntohs( firstnet ), ntohs( lastnet ),
689                             ntohs( iface->i_rt->rt_firstnet ),
690                             ntohs( iface->i_rt->rt_lastnet ));
691                     syslog( LOG_ERR, "Seed error! Exiting!" );
692                     return -1;
693                 }
694
695
696                 /*
697                  * It is possible that we will corrupt our route database
698                  * by just forcing this change.  A better solution would
699                  * be to search all of our current routes, looking for
700                  * this new route, and delete any old versions.  Also, we
701                  * would call rtmp_delete() on the old net range, in case
702                  * there is some other net which actually had that range.  XXX
703                  */
704                 iface->i_rt->rt_firstnet = firstnet;
705                 iface->i_rt->rt_lastnet = lastnet;
706
707                 if ( ntohs( iface->i_addr.sat_addr.s_net ) <
708                         ntohs( firstnet ) ||
709                         ntohs( iface->i_addr.sat_addr.s_net ) >
710                         ntohs( lastnet )) {
711                     iface->i_addr.sat_addr.s_net = 0;   /* ATADDR_ANYNET? */
712                 }
713                 setaddr( iface, IFACE_PHASE2, iface->i_addr.sat_addr.s_net,
714                         iface->i_addr.sat_addr.s_node, firstnet, lastnet );
715                 stabletimer = UNSTABLE;
716             }
717
718             /* add addr to loopback route */
719             if ( looproute( iface, RTMP_ADD )) { /* -1 or 1 */
720                 syslog( LOG_ERR,
721                         "zip_packet: can't route %u.%u to loopback: %m",
722                         ntohs( iface->i_addr.sat_addr.s_net ),
723                         iface->i_addr.sat_addr.s_node );
724                 return -1;
725             }
726
727             syslog( LOG_INFO, "zip_packet configured %s from %u.%u",
728                     iface->i_name, ntohs( from->sat_addr.s_net ),
729                     from->sat_addr.s_node );
730             iface->i_flags |= IFACE_CONFIG;
731             if ( iface == ciface ) {
732                 ciface = ciface->i_next;
733                 bootaddr( ciface );
734             }
735             break;
736
737         case ZIPOP_NOTIFY :
738 #ifdef DEBUG
739             printf( "zip notify from %u.%u\n", ntohs( from->sat_addr.s_net ),
740                     from->sat_addr.s_node );
741 #endif /* DEBUG */
742             break;
743
744         default :
745             syslog( LOG_INFO, "zip_packet bad zip op from %u.%u\n",
746                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
747         }
748         break;
749
750     case DDPTYPE_ATP :
751         if ( data + sizeof( struct atphdr ) > end ) {
752             syslog( LOG_INFO, "zip atp malformed packet" );
753             return 1;
754         }
755         memcpy( &ah, data, sizeof( struct atphdr ));
756         data += sizeof( struct atphdr );
757         if ( ah.atphd_ctrlinfo != ATP_TREQ ) {
758             syslog( LOG_INFO, "zip atp bad control" );
759             return 1;
760         }
761         ah.atphd_ctrlinfo = ATP_TRESP | ATP_EOM;
762         if ( ah.atphd_bitmap != 1 ) {
763             syslog( LOG_ERR, "zip atp bad bitmap" );
764             return 1;
765         }
766         ah.atphd_bitmap = 0;
767
768         zipop = *data++;
769         data++;
770         memcpy( &index, data, sizeof( u_short ));
771         data += sizeof( u_short );
772         index = ntohs( index );
773         if ( data != end ) {
774             syslog( LOG_INFO, "zip atp malformed packet" );
775             return 1;
776         }
777
778         data = packet;
779         end = data + sizeof( packet );
780         *data++ = DDPTYPE_ATP;
781         memcpy( data, &ah, sizeof( struct atphdr ));
782         data += sizeof( struct atphdr );
783         lastflag = data++;              /* mark and space for last flag */
784         *data++ = 0;
785         nzones = data;                  /* mark and space for zone count */
786         data += sizeof( u_short );
787
788         switch ( zipop ) {
789         case ZIPOP_GETMYZONE :
790             if ( index != 0 ) {
791                 syslog( LOG_INFO, "zip atp gmz bad index" );
792                 return 1;
793             }
794
795             if ( iface->i_flags & IFACE_LOOPBACK ) {
796                 iface = interfaces->i_next;     /* first interface */
797             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
798                     ntohs( from->sat_addr.s_net ) ||
799                     ntohs( iface->i_rt->rt_lastnet ) <
800                     ntohs( from->sat_addr.s_net )) {
801                 return 0;
802             }
803
804             if ( iface->i_rt->rt_zt == 0 ) {
805                 return 0;
806             }
807             zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
808             if ( data + 1 + zt->zt_len > end ) {
809                 syslog( LOG_INFO, "zip atp gmz reply too long" );
810                 return 1;
811             }
812             *data++ = zt->zt_len;
813             memcpy( data, zt->zt_name, zt->zt_len );
814             data += zt->zt_len;
815
816             *lastflag = 0;
817             nz = 1;
818             break;
819
820         case ZIPOP_GETZONELIST :
821             for ( zt = ziptab; zt && ( index > 1 ); zt = zt->zt_next, index-- )
822                 ;
823             for ( nz = 0; zt; zt = zt->zt_next, nz++ ) {
824                 if ( data + 1 + zt->zt_len > end ) {
825                     break;
826                 }
827                 *data++ = zt->zt_len;
828                 memcpy( data, zt->zt_name, zt->zt_len );
829                 data += zt->zt_len;
830             }
831
832             *lastflag = ( zt == 0 );            /* Too clever? */
833             break;
834
835         case ZIPOP_GETLOCALZONES :
836             if ( iface->i_flags & IFACE_LOOPBACK ) {
837                 iface = interfaces->i_next;     /* first interface */
838             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
839                     ntohs( from->sat_addr.s_net ) ||
840                     ntohs( iface->i_rt->rt_lastnet ) <
841                     ntohs( from->sat_addr.s_net )) {
842                 return 0;
843             }
844
845             for ( l = iface->i_rt->rt_zt; l && ( index > 1 );
846                     l = l->l_next, index-- )
847                 ;
848             for ( nz = 0; l; l = l->l_next, nz++ ) {
849                 zt = (struct ziptab *)l->l_data;
850                 if ( data + 1 + zt->zt_len > end ) {
851                     break;
852                 }
853                 *data++ = zt->zt_len;
854                 memcpy( data, zt->zt_name, zt->zt_len );
855                 data += zt->zt_len;
856             }
857
858             *lastflag = ( l == 0 );
859             break;
860
861         default :
862             syslog( LOG_INFO, "zip atp bad option" );
863             return 1;
864         }
865
866         /* send reply */
867         if ( nz > 0 ) {
868             nz = htons( nz );
869             memcpy( nzones, &nz, sizeof( u_short ));
870             if ( sendto( ap->ap_fd, packet, data - packet, 0,
871                     (struct sockaddr *)from,
872                     sizeof( struct sockaddr_at )) < 0 ) {
873                 syslog( LOG_ERR, "zip atp sendto %u.%u: %m",
874                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
875                 return 1;
876             }
877         }
878         break;
879
880     default :
881         syslog( LOG_INFO, "zip_packet bad ddp type from %u.%u\n",
882                 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
883         return 1;
884     }
885
886     return 0;
887 }
888
889 int zip_getnetinfo( iface )
890     struct interface    *iface;
891 {
892     struct atport       *ap;
893     struct ziphdr       zh;
894     struct sockaddr_at  sat;
895     char                *data, packet[ 40 ];
896     u_short             net;
897
898     syslog( LOG_INFO, "zip_getnetinfo for %s", iface->i_name );
899
900     for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
901         if ( ap->ap_packet == zip_packet ) {
902             break;
903         }
904     }
905     if ( ap == 0 ) {
906         syslog( LOG_ERR, "zip_getnetinfo can't find zip socket!" );
907         return -1;
908     }
909
910     data = packet;
911
912     *data++ = DDPTYPE_ZIP;
913
914     zh.zh_op = ZIPOP_GNI;
915     zh.zh_zero = 0;
916     memcpy( data, &zh, sizeof( struct ziphdr ));
917     data += sizeof( struct ziphdr );
918     net = 0;
919     memcpy( data, &net, sizeof( u_short ));
920     data += sizeof( u_short );
921     memcpy( data, &net, sizeof( u_short ));
922     data += sizeof( u_short );
923
924     /*
925      * Set our requesting zone to NULL, so the response will contain
926      * the default zone.
927      */
928     *data++ = 0;
929
930 #ifdef BSD4_4
931     sat.sat_len = sizeof( struct sockaddr_at );
932 #endif /* BSD4_4 */
933     sat.sat_family = AF_APPLETALK;
934     sat.sat_addr.s_net = 0;
935     sat.sat_addr.s_node = ATADDR_BCAST;
936     sat.sat_port = ap->ap_port;
937
938     if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
939             sizeof( struct sockaddr_at )) < 0 ) {
940         syslog( LOG_ERR, "zip_getnetinfo sendto: %m" );
941         return -1;
942     }
943     return 0;
944 }
945
946     struct ziptab *
947 newzt( len, name )
948     const int           len;
949     const char  *name;
950 {
951     struct ziptab       *zt;
952
953     if (( zt = (struct ziptab *)calloc(1, sizeof( struct ziptab ))) == NULL ) {
954         return( NULL );
955     }
956
957     zt->zt_len = len;
958     if (( zt->zt_name = (char *)malloc( len )) == NULL ) {
959         free(zt);
960         return( NULL );
961     }
962
963     memcpy( zt->zt_name, name, len );
964     return( zt );
965 }
966
967
968 /*
969  * Insert at the end.  Return 1 if a mapping already exists, 0 otherwise.
970  * -1 on error.
971  */
972 static int add_list( head, data )
973     struct list **head;
974     void        *data;
975 {
976     struct list *l, *l2;
977
978     for ( l = *head; l; l = l->l_next ) {
979         if ( l->l_data == data ) {
980             return( 1 );
981         }
982     }
983     if (( l = (struct list *)malloc( sizeof( struct list ))) == NULL ) {
984         syslog( LOG_ERR, "add_list malloc: %m" );
985         return -1;
986     }
987
988     l->l_data = data;
989     l->l_next = NULL;
990     if ( *head == NULL ) {
991         l->l_prev = NULL;
992         *head = l;
993     } else {
994         /* find end of list */
995         for ( l2 = *head; l2->l_next; l2 = l2->l_next )
996             ;
997         l->l_prev = l2;
998         l2->l_next = l;
999     }
1000     return( 0 );
1001 }
1002
1003 int addzone( rt, len, zone )
1004     struct rtmptab      *rt;
1005     int                 len;
1006     char                *zone;
1007 {
1008     struct ziptab       *zt;
1009     int                 cc, exists = 0;
1010
1011     for ( zt = ziptab; zt; zt = zt->zt_next ) {
1012         if ( zt->zt_len == len &&
1013                 strndiacasecmp( zt->zt_name, zone, len ) == 0 ) {
1014             break;
1015         }
1016     }
1017     if ( zt == NULL ) {
1018         if (( zt = newzt( len, zone )) == NULL ) {
1019             syslog( LOG_ERR, "addzone newzt: %m" );
1020             return -1;
1021         }
1022         if ( ziptab == NULL ) {
1023             zt->zt_prev = NULL;
1024             ziptab = zt;
1025         } else {
1026             zt->zt_prev = ziplast;
1027             ziplast->zt_next = zt;
1028         }
1029         ziplast = zt;
1030     }
1031
1032     if ((cc = add_list( &zt->zt_rt, rt )) < 0) 
1033       return -1;
1034
1035     if (cc)
1036       exists++;
1037
1038     if ((cc = add_list( &rt->rt_zt, zt )) < 0 )
1039       return -1;
1040
1041     if (cc) {
1042         if ( !exists ) {
1043             syslog( LOG_ERR, "addzone corrupted route/zone mapping" );
1044             return -1;
1045         }
1046         /*
1047          * We get the repeat for local nets which have zone information
1048          * already: we ask anyway, just to make sure.
1049          */
1050         
1051         return 0;
1052     }
1053     if ( exists ) {
1054         syslog( LOG_ERR, "addzone corrupted zone/route mapping" );
1055         return -1;
1056     }
1057     return 0;
1058 }