2 * $Id: zip.c,v 1.8 2001-12-10 20:16:55 srittau Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #include <sys/param.h>
16 #include <sys/types.h>
17 #include <sys/syslog.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
23 #include <net/route.h>
26 #include <net/route.h>
27 #include <netatalk/endian.h>
28 #include <netatalk/at.h>
31 #include <sys/sockio.h>
34 #include <atalk/ddp.h>
35 #include <atalk/zip.h>
36 #include <atalk/atp.h>
37 #include <atalk/util.h>
40 #include "interface.h"
45 #include "multicast.h"
48 struct ziptab *ziptab = NULL, *ziplast = NULL;
51 static int zonecheck( rtmp, iface )
53 struct interface *iface;
56 struct ziptab *czt, *zt;
59 if (( iface->i_flags & IFACE_SEED ) == 0 ) {
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 )) {
72 syslog( LOG_ERR, "zonecheck: %.*s not in zone list", czt->zt_len,
74 return( -1 ); /* configured zone not found in net zones */
78 for ( ztcnt = 0, l = rtmp->rt_zt; l; l = l->l_next, ztcnt++ )
81 if ( cztcnt != ztcnt ) {
82 syslog( LOG_ERR, "zonecheck: %d configured zones, %d zones found",
84 return( -1 ); /* more net zones than configured zones */
91 int zip_packet( ap, from, data, len )
93 struct sockaddr_at *from;
99 struct interface *iface;
101 struct rtmptab *rtmp;
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;
113 syslog( LOG_INFO, "zip_packet malformed packet" );
118 iface = ap->ap_iface;
122 if ( data + sizeof( struct ziphdr ) > end ) {
123 syslog( LOG_INFO, "zip_packet malformed packet" );
126 memcpy( &zh, data, sizeof( struct ziphdr ));
127 data += sizeof( struct ziphdr );
129 switch ( zh.zh_op ) {
133 rend = packet + sizeof( packet );
134 *reply++ = DDPTYPE_ZIP;
141 while ( data + sizeof( u_short ) <= end && qcnt-- > 0 ) {
142 memcpy( &firstnet, data, sizeof( u_short ));
143 data += sizeof( u_short );
146 * Look for the given network number (firstnet).
147 * Perhaps we could do better than brute force?
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 ) {
164 * Count the number of zones in this list, and the
165 * number of byte it will consume in a reply.
167 for ( zsz = 0, zcnt = 0, l = rtmp->rt_zt; l; l = l->l_next ) {
169 zt = (struct ziptab *)l->l_data;
170 zsz += sizeof( u_short ) + 1 + zt->zt_len;
174 * We might send this list in the current reply, as the
175 * first thing in the next reply, or as an extended packet.
177 if ( reply + zsz > rend ) {
179 zh.zh_op = ZIPOP_REPLY;
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 syslog( LOG_ERR, "zip reply sendto: %s",
193 if ( reply + zsz > rend ) {
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 >
199 zh.zh_op = ZIPOP_EREPLY;
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 syslog( LOG_ERR, "zip reply sendto: %s",
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 );
221 zh.zh_op = ZIPOP_EREPLY;
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 syslog( LOG_ERR, "zip reply sendto: %s",
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 );
249 zh.zh_op = ZIPOP_REPLY;
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 syslog( LOG_ERR, "zip reply sendto: %s",
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 ) {
269 if ( gate == NULL ) {
270 syslog( LOG_INFO, "zip reply from non-gateway %u.%u",
271 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
278 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
279 syslog( LOG_INFO, "zip reply short (%d)", len );
282 memcpy( &firstnet, data, sizeof( u_short ));
283 data += sizeof( u_short );
285 if ( rtmp && rtmp->rt_firstnet != firstnet ) {
287 if ( rtmp->rt_gate == NULL &&
288 zonecheck( rtmp, gate->g_iface ) != 0 ) {
289 syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
292 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
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;
299 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
300 if ( rtmp->rt_firstnet == firstnet ) {
306 * Update head to this rtmp entry.
308 if ( rtmp != 0 && gate->g_rt != rtmp ) {
309 gate->g_rt->rt_prev->rt_next = gate->g_rt;
311 rtmp->rt_prev->rt_next = 0;
316 if ( zlen > 32 || zlen <= 0 ) {
317 syslog( LOG_INFO, "zip reply bad packet" );
320 if ( data + zlen > end ) {
321 syslog( LOG_INFO, "zip reply short (%d)", len );
324 memcpy( zname, data, zlen );
328 * We won't find any rtmp entry if the gateway is no longer
329 * telling us about the entry.
332 syslog( LOG_INFO, "zip skip reply %u from %u.%u (no rtmp)",
333 ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
334 from->sat_addr.s_node );
336 * Check if the route is still in use (the iprev check is
337 * no good if rtmp is the interface's route).
339 } else if ( rtmp->rt_iprev == NULL && rtmp->rt_prev != NULL ) {
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 );
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).
351 } else if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
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 );
359 if (addzone( rtmp, zlen, zname ) < 0) {
360 syslog(LOG_ERR, "zip_packet: addzone");
363 rtmp->rt_flags |= RTMPTAB_HASZONES;
365 } while ( data < end );
367 if ( rtmp && rtmp->rt_flags & RTMPTAB_HASZONES ) {
369 if ( rtmp->rt_gate == 0 &&
370 zonecheck( rtmp, gate->g_iface ) != 0 ) {
371 syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
374 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
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 ) {
386 if ( gate == NULL ) {
387 syslog( LOG_INFO, "zip ereply from non-gateway %u.%u",
388 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
393 * Note that we're not advancing "data" here. We do that
394 * at the top of the do-while loop, below.
396 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
397 syslog( LOG_INFO, "zip ereply short (%d)", len );
400 memcpy( &firstnet, data, sizeof( u_short ));
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;
406 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
407 if ( rtmp->rt_firstnet == firstnet ) {
411 if ( rtmp == NULL ) {
412 syslog( LOG_INFO, "zip ereply %u from %u.%u (no rtmp)",
413 ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
414 from->sat_addr.s_node );
417 if ( rtmp->rt_iprev == 0 ) {
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 );
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;
434 if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
435 syslog( LOG_INFO, "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 );
445 * We copy out firstnet, twice (see above). Not
446 * a big deal, and it makes the end condition cleaner.
448 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
449 syslog( LOG_INFO, "zip ereply short (%d)", len );
452 memcpy( &firstnet, data, sizeof( u_short ));
453 data += sizeof( u_short );
456 if ( firstnet != rtmp->rt_firstnet ) {
457 syslog( LOG_INFO, "zip ereply with multiple nets" );
462 if ( zlen > 32 || zlen <= 0 ) {
463 syslog( LOG_INFO, "zip ereply bad zone length (%d)", zlen );
466 if ( data + zlen > end ) {
467 syslog( LOG_INFO, "zip ereply short (%d)", len );
470 memcpy( zname, data, zlen );
472 if (addzone( rtmp, zlen, zname ) < 0) {
473 syslog(LOG_ERR, "zip_packet: addzone");
476 } while ( data < end );
480 * Count zones for rtmptab entry.
482 for ( n = 0, l = rtmp->rt_zt; l; l = l->l_next, n++ )
484 if ( n == zh.zh_count ) {
485 rtmp->rt_flags |= RTMPTAB_HASZONES;
487 if ( rtmp->rt_gate == 0 &&
488 zonecheck( rtmp, gate->g_iface ) != 0 ) {
489 syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
492 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
499 * Don't answer with bogus information.
501 if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
502 iface->i_rt->rt_zt == 0 ||
503 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
507 if ( zh.zh_zero != 0 || data + 2 * sizeof( u_short ) > end ) {
508 syslog( LOG_INFO, "zip_packet malformed packet" );
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 syslog( LOG_INFO, "zip_packet malformed packet" );
522 if ( zlen < 0 || zlen > 32 ) {
523 syslog( LOG_INFO, "zip_packet malformed packet" );
526 memcpy( zname, data, zlen );
529 end = data + sizeof( packet );
530 zh.zh_op = ZIPOP_GNIREPLY;
534 * Skip to the nets. Fill in header when we're done.
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 );
543 memcpy( data, zname, zlen );
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.
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 ) {
559 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
560 zh.zh_flags |= ZIPGNI_INVALID;
563 for ( n = 0, l = iface->i_rt->rt_zt; l; l = l->l_next, n++ )
566 zh.zh_flags |= ZIPGNI_ONEZONE;
570 *data++ = 6; /* sizeof ??? */
571 if (zone_bcast(zt) < 0) {
572 syslog(LOG_ERR, "zip_packet: zone_bcast");
575 memcpy(data, zt->zt_bcast, 6);
581 if ( zh.zh_flags & ZIPGNI_INVALID ) {
582 *data++ = zt->zt_len;
583 memcpy( data, zt->zt_name, zt->zt_len );
588 *packet = DDPTYPE_ZIP;
589 memcpy( packet + 1, &zh, sizeof( struct ziphdr ));
592 * If the address we received this request from isn't correct
593 * for the net we received it on, send a broadcast.
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;
603 if ( sendto( ap->ap_fd, packet, data - packet, 0,
604 (struct sockaddr *)from,
605 sizeof( struct sockaddr_at )) < 0 ) {
606 syslog( LOG_ERR, "zip gni sendto %u.%u: %s",
607 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
613 case ZIPOP_GNIREPLY :
615 * Ignore ZIP GNIReplys which are either late or unsolicited.
617 syslog( LOG_DEBUG, "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 );
621 if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) ||
622 ( iface->i_flags & IFACE_ADDR ) == 0 ) {
623 syslog( LOG_DEBUG, "zip ignoring gnireply" );
627 if ( data + 2 * sizeof( u_short ) > end ) {
628 syslog( LOG_INFO, "zip_packet malformed packet" );
631 memcpy( &firstnet, data, sizeof( u_short ));
632 data += sizeof( u_short );
633 memcpy( &lastnet, data, sizeof( u_short ));
634 data += sizeof( u_short );
637 * We never ask for a zone, so we can get back what the
640 if ( data >= end || data + *data > end ) {
641 syslog( LOG_INFO, "zip_packet malformed packet" );
644 if ( *data++ != 0 ) {
645 syslog( LOG_INFO, "zip_packet unsolicited zone" );
649 /* skip multicast (should really check it) */
650 if ( data >= end || data + *data > end ) {
651 syslog( LOG_INFO, "zip_packet malformed packet" );
656 if ( data >= end || data + *data > end ) {
657 syslog( LOG_INFO, "zip_packet malformed packet" );
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.
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 syslog( LOG_ERR, "default zone mismatch on %s",
674 syslog( LOG_ERR, "%.*s != %.*s",
675 iface->i_czt->zt_len, iface->i_czt->zt_name,
677 syslog( LOG_ERR, "Seed error! Exiting!" );
682 if (addzone( iface->i_rt, *data, data + 1 ) < 0) {
683 syslog(LOG_ERR, "zip_packet: addzone");
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.
692 if ( firstnet != iface->i_rt->rt_firstnet ||
693 lastnet != iface->i_rt->rt_lastnet ) {
694 if ( iface->i_flags & IFACE_SEED ) {
695 syslog( LOG_ERR, "netrange mismatch on %s",
697 syslog( LOG_ERR, "%u-%u != %u-%u",
698 ntohs( firstnet ), ntohs( lastnet ),
699 ntohs( iface->i_rt->rt_firstnet ),
700 ntohs( iface->i_rt->rt_lastnet ));
701 syslog( LOG_ERR, "Seed error! Exiting!" );
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
714 iface->i_rt->rt_firstnet = firstnet;
715 iface->i_rt->rt_lastnet = lastnet;
717 if ( ntohs( iface->i_addr.sat_addr.s_net ) <
719 ntohs( iface->i_addr.sat_addr.s_net ) >
721 iface->i_addr.sat_addr.s_net = 0; /* ATADDR_ANYNET? */
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;
728 /* add addr to loopback route */
729 if ( looproute( iface, RTMP_ADD )) { /* -1 or 1 */
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,
738 syslog( LOG_INFO, "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;
750 printf( "zip notify from %u.%u\n", ntohs( from->sat_addr.s_net ),
751 from->sat_addr.s_node );
756 syslog( LOG_INFO, "zip_packet bad zip op from %u.%u\n",
757 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
762 if ( data + sizeof( struct atphdr ) > end ) {
763 syslog( LOG_INFO, "zip atp malformed packet" );
766 memcpy( &ah, data, sizeof( struct atphdr ));
767 data += sizeof( struct atphdr );
768 if ( ah.atphd_ctrlinfo != ATP_TREQ ) {
769 syslog( LOG_INFO, "zip atp bad control" );
772 ah.atphd_ctrlinfo = ATP_TRESP | ATP_EOM;
773 if ( ah.atphd_bitmap != 1 ) {
774 syslog( LOG_ERR, "zip atp bad bitmap" );
781 memcpy( &index, data, sizeof( u_short ));
782 data += sizeof( u_short );
783 index = ntohs( index );
785 syslog( LOG_INFO, "zip atp malformed 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 */
796 nzones = data; /* mark and space for zone count */
797 data += sizeof( u_short );
800 case ZIPOP_GETMYZONE :
802 syslog( LOG_INFO, "zip atp gmz bad index" );
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 )) {
815 if ( iface->i_rt->rt_zt == 0 ) {
818 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
819 if ( data + 1 + zt->zt_len > end ) {
820 syslog( LOG_INFO, "zip atp gmz reply too long" );
823 *data++ = zt->zt_len;
824 memcpy( data, zt->zt_name, zt->zt_len );
831 case ZIPOP_GETZONELIST :
832 for ( zt = ziptab; zt && ( index > 1 ); zt = zt->zt_next, index-- )
834 for ( nz = 0; zt; zt = zt->zt_next, nz++ ) {
835 if ( data + 1 + zt->zt_len > end ) {
838 *data++ = zt->zt_len;
839 memcpy( data, zt->zt_name, zt->zt_len );
843 *lastflag = ( zt == 0 ); /* Too clever? */
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 )) {
856 for ( l = iface->i_rt->rt_zt; l && ( index > 1 );
857 l = l->l_next, index-- )
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 ) {
864 *data++ = zt->zt_len;
865 memcpy( data, zt->zt_name, zt->zt_len );
869 *lastflag = ( l == 0 );
873 syslog( LOG_INFO, "zip atp bad option" );
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 syslog( LOG_ERR, "zip atp sendto %u.%u: %s",
885 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
893 syslog( LOG_INFO, "zip_packet bad ddp type from %u.%u\n",
894 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
901 int zip_getnetinfo( iface )
902 struct interface *iface;
906 struct sockaddr_at sat;
907 char *data, packet[ 40 ];
910 syslog( LOG_INFO, "zip_getnetinfo for %s", iface->i_name );
912 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
913 if ( ap->ap_packet == zip_packet ) {
918 syslog( LOG_ERR, "zip_getnetinfo can't find zip socket!" );
924 *data++ = DDPTYPE_ZIP;
926 zh.zh_op = ZIPOP_GNI;
928 memcpy( data, &zh, sizeof( struct ziphdr ));
929 data += sizeof( struct ziphdr );
931 memcpy( data, &net, sizeof( u_short ));
932 data += sizeof( u_short );
933 memcpy( data, &net, sizeof( u_short ));
934 data += sizeof( u_short );
937 * Set our requesting zone to NULL, so the response will contain
943 sat.sat_len = sizeof( struct sockaddr_at );
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;
950 if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
951 sizeof( struct sockaddr_at )) < 0 ) {
952 syslog( LOG_ERR, "zip_getnetinfo sendto: %s", strerror(errno) );
965 if (( zt = (struct ziptab *)calloc(1, sizeof( struct ziptab ))) == NULL ) {
970 if (( zt->zt_name = (char *)malloc( len )) == NULL ) {
975 memcpy( zt->zt_name, name, len );
981 * Insert at the end. Return 1 if a mapping already exists, 0 otherwise.
984 static int add_list( head, data )
990 for ( l = *head; l; l = l->l_next ) {
991 if ( l->l_data == data ) {
995 if (( l = (struct list *)malloc( sizeof( struct list ))) == NULL ) {
996 syslog( LOG_ERR, "add_list malloc: %s", strerror(errno) );
1002 if ( *head == NULL ) {
1006 /* find end of list */
1007 for ( l2 = *head; l2->l_next; l2 = l2->l_next )
1015 int addzone( rt, len, zone )
1023 for ( zt = ziptab; zt; zt = zt->zt_next ) {
1024 if ( zt->zt_len == len &&
1025 strndiacasecmp( zt->zt_name, zone, len ) == 0 ) {
1030 if (( zt = newzt( len, zone )) == NULL ) {
1031 syslog( LOG_ERR, "addzone newzt: %s", strerror(errno) );
1034 if ( ziptab == NULL ) {
1038 zt->zt_prev = ziplast;
1039 ziplast->zt_next = zt;
1044 if ((cc = add_list( &zt->zt_rt, rt )) < 0)
1050 if ((cc = add_list( &rt->rt_zt, zt )) < 0 )
1055 syslog( LOG_ERR, "addzone corrupted route/zone mapping" );
1059 * We get the repeat for local nets which have zone information
1060 * already: we ask anyway, just to make sure.
1066 syslog( LOG_ERR, "addzone corrupted zone/route mapping" );