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