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