2 * $Id: zip.c,v 1.13 2009-10-13 22:55:37 didg 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 <atalk/logger.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(struct rtmptab *rtmp, struct interface *iface)
54 struct ziptab *czt, *zt;
57 if (( iface->i_flags & IFACE_SEED ) == 0 ) {
61 for ( cztcnt = 0, czt = iface->i_czt; czt; czt = czt->zt_next, cztcnt++ ) {
62 for ( l = rtmp->rt_zt; l; l = l->l_next ) {
63 zt = (struct ziptab *)l->l_data;
64 if ( czt->zt_len == zt->zt_len &&
65 !strndiacasecmp( czt->zt_name, zt->zt_name, czt->zt_len )) {
70 LOG(log_error, logtype_atalkd, "zonecheck: %.*s not in zone list", czt->zt_len,
72 return( -1 ); /* configured zone not found in net zones */
76 for ( ztcnt = 0, l = rtmp->rt_zt; l; l = l->l_next, ztcnt++ )
79 if ( cztcnt != ztcnt ) {
80 LOG(log_error, logtype_atalkd, "zonecheck: %d configured zones, %d zones found",
82 return( -1 ); /* more net zones than configured zones */
89 int zip_packet(struct atport *ap,struct sockaddr_at *from, char *data, int len)
93 struct interface *iface;
95 struct rtmptab *rtmp = NULL;
98 u_short firstnet, lastnet, index, nz;
99 char *end, zname[ 32 ], packet[ ATP_BUFSIZ ], *nzones, *lastflag;
100 char *reply, *rend, *ziphdr;
101 int zlen, n, zipop, rcnt, qcnt, zcnt, zsz;
102 extern int stabletimer;
107 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
112 iface = ap->ap_iface;
116 if ( data + sizeof( struct ziphdr ) > end ) {
117 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
120 memcpy( &zh, data, sizeof( struct ziphdr ));
121 data += sizeof( struct ziphdr );
123 switch ( zh.zh_op ) {
127 rend = packet + sizeof( packet );
128 *reply++ = DDPTYPE_ZIP;
135 while ( data + sizeof( u_short ) <= end && qcnt-- > 0 ) {
136 memcpy( &firstnet, data, sizeof( u_short ));
137 data += sizeof( u_short );
140 * Look for the given network number (firstnet).
141 * Perhaps we could do better than brute force?
143 for ( iface = interfaces; iface; iface = iface->i_next ) {
144 for ( rtmp = iface->i_rt; rtmp; rtmp = rtmp->rt_inext ) {
145 if ( firstnet == rtmp->rt_firstnet ) {
158 * Count the number of zones in this list, and the
159 * number of byte it will consume in a reply.
161 for ( zsz = 0, zcnt = 0, l = rtmp->rt_zt; l; l = l->l_next ) {
163 zt = (struct ziptab *)l->l_data;
164 zsz += sizeof( u_short ) + 1 + zt->zt_len;
168 * We might send this list in the current reply, as the
169 * first thing in the next reply, or as an extended packet.
171 if ( reply + zsz > rend ) {
173 zh.zh_op = ZIPOP_REPLY;
175 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
176 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
177 (struct sockaddr *)from,
178 sizeof( struct sockaddr_at )) < 0 ) {
179 LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
187 if ( reply + zsz > rend ) {
189 for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
190 zt = (struct ziptab *)l->l_data;
191 if ( reply + sizeof( u_short ) + 1 + zt->zt_len >
193 zh.zh_op = ZIPOP_EREPLY;
195 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
196 if ( sendto( ap->ap_fd, packet, reply - packet,
197 0, (struct sockaddr *)from,
198 sizeof( struct sockaddr_at )) < 0 ) {
199 LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
207 memcpy( reply, &firstnet, sizeof( u_short ));
208 reply += sizeof( u_short );
209 *reply++ = zt->zt_len;
210 memcpy( reply, zt->zt_name, zt->zt_len );
215 zh.zh_op = ZIPOP_EREPLY;
217 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
218 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
219 (struct sockaddr *)from,
220 sizeof( struct sockaddr_at )) < 0 ) {
221 LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
232 for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
233 zt = (struct ziptab *)l->l_data;
234 memcpy( reply, &firstnet, sizeof( u_short ));
235 reply += sizeof( u_short );
236 *reply++ = zt->zt_len;
237 memcpy( reply, zt->zt_name, zt->zt_len );
243 zh.zh_op = ZIPOP_REPLY;
245 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
246 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
247 (struct sockaddr *)from,
248 sizeof( struct sockaddr_at )) < 0 ) {
249 LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
256 for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
257 if (( from->sat_addr.s_net == 0 ||
258 gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
259 gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
263 if ( gate == NULL ) {
264 LOG(log_info, logtype_atalkd, "zip reply from non-gateway %u.%u",
265 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
272 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
273 LOG(log_info, logtype_atalkd, "zip reply short (%d)", len );
276 memcpy( &firstnet, data, sizeof( u_short ));
277 data += sizeof( u_short );
279 if ( rtmp && rtmp->rt_firstnet != firstnet ) {
281 if ( rtmp->rt_gate == NULL &&
282 zonecheck( rtmp, gate->g_iface ) != 0 ) {
283 LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
286 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
289 /* Check if this is the interface's route. */
290 if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
291 rtmp = gate->g_iface->i_rt;
293 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
294 if ( rtmp->rt_firstnet == firstnet ) {
300 * Update head to this rtmp entry.
302 if ( rtmp != 0 && gate->g_rt != rtmp ) {
303 gate->g_rt->rt_prev->rt_next = gate->g_rt;
305 rtmp->rt_prev->rt_next = 0;
310 if ( zlen > 32 || zlen <= 0 ) {
311 LOG(log_info, logtype_atalkd, "zip reply bad packet" );
314 if ( data + zlen > end ) {
315 LOG(log_info, logtype_atalkd, "zip reply short (%d)", len );
318 memcpy( zname, data, zlen );
322 * We won't find any rtmp entry if the gateway is no longer
323 * telling us about the entry.
326 LOG(log_info, logtype_atalkd, "zip skip reply %u from %u.%u (no rtmp)",
327 ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
328 from->sat_addr.s_node );
330 * Check if the route is still in use (the iprev check is
331 * no good if rtmp is the interface's route).
333 } else if ( rtmp->rt_iprev == NULL && rtmp->rt_prev != NULL ) {
334 LOG(log_info, logtype_atalkd,
335 "zip skip reply %u-%u from %u.%u (rtmp not in use)",
336 ntohs( rtmp->rt_firstnet ),
337 ntohs( rtmp->rt_lastnet ),
338 ntohs( from->sat_addr.s_net ),
339 from->sat_addr.s_node );
341 * Check if we've got an outstanding query for this route.
342 * We will often get this, since we ask every router on a
343 * net to verify our interface's zone(s).
345 } else if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
346 LOG(log_info, logtype_atalkd,
347 "zip skip reply %u-%u from %u.%u (no query)",
348 ntohs( rtmp->rt_firstnet ),
349 ntohs( rtmp->rt_lastnet ),
350 ntohs( from->sat_addr.s_net ),
351 from->sat_addr.s_node );
353 if (addzone( rtmp, zlen, zname ) < 0) {
354 LOG(log_error, logtype_atalkd, "zip_packet: addzone");
357 rtmp->rt_flags |= RTMPTAB_HASZONES;
359 } while ( data < end );
361 if ( rtmp && rtmp->rt_flags & RTMPTAB_HASZONES ) {
363 if ( rtmp->rt_gate == 0 &&
364 zonecheck( rtmp, gate->g_iface ) != 0 ) {
365 LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
368 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
373 for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
374 if (( from->sat_addr.s_net == 0 ||
375 gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
376 gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
380 if ( gate == NULL ) {
381 LOG(log_info, logtype_atalkd, "zip ereply from non-gateway %u.%u",
382 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
387 * Note that we're not advancing "data" here. We do that
388 * at the top of the do-while loop, below.
390 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
391 LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
394 memcpy( &firstnet, data, sizeof( u_short ));
396 /* Check if this is the interface's route. */
397 if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
398 rtmp = gate->g_iface->i_rt;
400 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
401 if ( rtmp->rt_firstnet == firstnet ) {
405 if ( rtmp == NULL ) {
406 LOG(log_info, logtype_atalkd, "zip ereply %u from %u.%u (no rtmp)",
407 ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
408 from->sat_addr.s_node );
411 if ( rtmp->rt_iprev == 0 ) {
412 LOG(log_info, logtype_atalkd,
413 "zip ereply %u-%u from %u.%u (rtmp not in use)",
414 ntohs( rtmp->rt_firstnet ),
415 ntohs( rtmp->rt_lastnet ),
416 ntohs( from->sat_addr.s_net ),
417 from->sat_addr.s_node );
420 /* update head to *next* rtmp entry */
421 if ( rtmp->rt_next != 0 ) {
422 gate->g_rt->rt_prev->rt_next = gate->g_rt;
423 gate->g_rt = rtmp->rt_next;
428 if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
429 LOG(log_info, logtype_atalkd, "zip ereply %u-%u from %u.%u (no query)",
430 ntohs( rtmp->rt_firstnet ),
431 ntohs( rtmp->rt_lastnet ),
432 ntohs( from->sat_addr.s_net ),
433 from->sat_addr.s_node );
439 * We copy out firstnet, twice (see above). Not
440 * a big deal, and it makes the end condition cleaner.
442 if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
443 LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
446 memcpy( &firstnet, data, sizeof( u_short ));
447 data += sizeof( u_short );
450 if ( firstnet != rtmp->rt_firstnet ) {
451 LOG(log_info, logtype_atalkd, "zip ereply with multiple nets" );
456 if ( zlen > 32 || zlen <= 0 ) {
457 LOG(log_info, logtype_atalkd, "zip ereply bad zone length (%d)", zlen );
460 if ( data + zlen > end ) {
461 LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
464 memcpy( zname, data, zlen );
466 if (addzone( rtmp, zlen, zname ) < 0) {
467 LOG(log_error, logtype_atalkd, "zip_packet: addzone");
470 } while ( data < end );
474 * Count zones for rtmptab entry.
476 for ( n = 0, l = rtmp->rt_zt; l; l = l->l_next, n++ )
478 if ( n == zh.zh_count ) {
479 rtmp->rt_flags |= RTMPTAB_HASZONES;
481 if ( rtmp->rt_gate == 0 &&
482 zonecheck( rtmp, gate->g_iface ) != 0 ) {
483 LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
486 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
493 * Don't answer with bogus information.
495 if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
496 iface->i_rt->rt_zt == 0 ||
497 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
501 if ( zh.zh_zero != 0 || data + 2 * sizeof( u_short ) > end ) {
502 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
506 memcpy( &firstnet, data, sizeof( u_short ));
507 data += sizeof( u_short );
508 memcpy( &lastnet, data, sizeof( u_short ));
509 data += sizeof( u_short );
510 if ( firstnet != 0 || lastnet != 0 || data >= end ) {
511 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
516 if ( zlen < 0 || zlen > 32 ) {
517 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
520 memcpy( zname, data, zlen );
523 end = data + sizeof( packet );
524 zh.zh_op = ZIPOP_GNIREPLY;
528 * Skip to the nets. Fill in header when we're done.
530 data += 1 + sizeof( struct ziphdr );
531 memcpy( data, &iface->i_rt->rt_firstnet, sizeof( u_short ));
532 data += sizeof( u_short );
533 memcpy( data, &iface->i_rt->rt_lastnet, sizeof( u_short ));
534 data += sizeof( u_short );
537 memcpy( data, zname, zlen );
541 * Check if the given zone is valid. If it's valid, just fill in
542 * the multicast address. If it's not, fill the multicast address
543 * in with the default zone and return the default zone.
545 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
546 zt = (struct ziptab *)l->l_data;
547 if ( zt->zt_len == zlen &&
548 strndiacasecmp( zname, zt->zt_name, zlen ) == 0 ) {
553 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
554 zh.zh_flags |= ZIPGNI_INVALID;
557 for ( n = 0, l = iface->i_rt->rt_zt; l; l = l->l_next, n++ )
560 zh.zh_flags |= ZIPGNI_ONEZONE;
564 *data++ = 6; /* sizeof ??? */
565 if (zone_bcast(zt) < 0) {
566 LOG(log_error, logtype_atalkd, "zip_packet: zone_bcast");
569 memcpy(data, zt->zt_bcast, 6);
575 if ( zh.zh_flags & ZIPGNI_INVALID ) {
576 *data++ = zt->zt_len;
577 memcpy( data, zt->zt_name, zt->zt_len );
582 *packet = DDPTYPE_ZIP;
583 memcpy( packet + 1, &zh, sizeof( struct ziphdr ));
586 * If the address we received this request from isn't correct
587 * for the net we received it on, send a broadcast.
589 if ( ntohs( from->sat_addr.s_net ) <
590 ntohs( iface->i_rt->rt_firstnet ) ||
591 ntohs( from->sat_addr.s_net ) >
592 ntohs( iface->i_rt->rt_lastnet )) {
593 from->sat_addr.s_net = 0;
594 from->sat_addr.s_node = ATADDR_BCAST;
597 if ( sendto( ap->ap_fd, packet, data - packet, 0,
598 (struct sockaddr *)from,
599 sizeof( struct sockaddr_at )) < 0 ) {
600 LOG(log_error, logtype_atalkd, "zip gni sendto %u.%u: %s",
601 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
607 case ZIPOP_GNIREPLY :
609 * Ignore ZIP GNIReplys which are either late or unsolicited.
611 LOG(log_debug, logtype_atalkd, "zip gnireply from %u.%u (%s %x)",
612 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
613 iface->i_name, iface->i_flags );
615 if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) ||
616 ( iface->i_flags & IFACE_ADDR ) == 0 ) {
617 LOG(log_debug, logtype_atalkd, "zip ignoring gnireply" );
621 if ( data + 2 * sizeof( u_short ) > end ) {
622 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
625 memcpy( &firstnet, data, sizeof( u_short ));
626 data += sizeof( u_short );
627 memcpy( &lastnet, data, sizeof( u_short ));
628 data += sizeof( u_short );
631 * We never ask for a zone, so we can get back what the
634 if ( data >= end || data + *data > end ) {
635 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
638 if ( *data++ != 0 ) {
639 LOG(log_info, logtype_atalkd, "zip_packet unsolicited zone" );
643 /* skip multicast (should really check it) */
644 if ( data >= end || data + *data > end ) {
645 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
650 if ( data >= end || data + *data > end ) {
651 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
656 * First, if we're not seed, we always get our zone information
657 * from the net -- we don't even save what was in the file.
658 * Second, if we are seed, we keep our zone list in the
659 * interface structure, not in the zone table. This allows us
660 * to check that the net is giving us good zones.
662 if ( iface->i_flags & IFACE_SEED ) {
663 if ( iface->i_czt->zt_len != *data ||
664 strndiacasecmp( iface->i_czt->zt_name,
665 data + 1, *data ) != 0 ) {
666 LOG(log_error, logtype_atalkd, "default zone mismatch on %s",
668 LOG(log_error, logtype_atalkd, "%.*s != %.*s",
669 iface->i_czt->zt_len, iface->i_czt->zt_name,
671 LOG(log_error, logtype_atalkd, "Seed error! Exiting!" );
676 if (addzone( iface->i_rt, *data, data + 1 ) < 0) {
677 LOG(log_error, logtype_atalkd, "zip_packet: addzone");
682 * The netrange we received from the router doesn't match the
683 * range we have locally. This is not a problem, unless we
684 * have seed information.
686 if ( firstnet != iface->i_rt->rt_firstnet ||
687 lastnet != iface->i_rt->rt_lastnet ) {
688 if ( iface->i_flags & IFACE_SEED ) {
689 LOG(log_error, logtype_atalkd, "netrange mismatch on %s",
691 LOG(log_error, logtype_atalkd, "%u-%u != %u-%u",
692 ntohs( firstnet ), ntohs( lastnet ),
693 ntohs( iface->i_rt->rt_firstnet ),
694 ntohs( iface->i_rt->rt_lastnet ));
695 LOG(log_error, logtype_atalkd, "Seed error! Exiting!" );
701 * It is possible that we will corrupt our route database
702 * by just forcing this change. A better solution would
703 * be to search all of our current routes, looking for
704 * this new route, and delete any old versions. Also, we
705 * would call rtmp_delete() on the old net range, in case
706 * there is some other net which actually had that range. XXX
708 iface->i_rt->rt_firstnet = firstnet;
709 iface->i_rt->rt_lastnet = lastnet;
711 if ( ntohs( iface->i_addr.sat_addr.s_net ) <
713 ntohs( iface->i_addr.sat_addr.s_net ) >
715 iface->i_addr.sat_addr.s_net = 0; /* ATADDR_ANYNET? */
717 setaddr( iface, IFACE_PHASE2, iface->i_addr.sat_addr.s_net,
718 iface->i_addr.sat_addr.s_node, firstnet, lastnet );
719 stabletimer = UNSTABLE;
722 /* add addr to loopback route */
723 if ( looproute( iface, RTMP_ADD )) { /* -1 or 1 */
724 LOG(log_error, logtype_atalkd,
725 "zip_packet: can't route %u.%u to loopback: %s",
726 ntohs( iface->i_addr.sat_addr.s_net ),
727 iface->i_addr.sat_addr.s_node,
732 LOG(log_info, logtype_atalkd, "zip_packet configured %s from %u.%u",
733 iface->i_name, ntohs( from->sat_addr.s_net ),
734 from->sat_addr.s_node );
735 iface->i_flags |= IFACE_CONFIG;
736 if ( iface == ciface ) {
737 ciface = ciface->i_next;
744 printf( "zip notify from %u.%u\n", ntohs( from->sat_addr.s_net ),
745 from->sat_addr.s_node );
750 LOG(log_info, logtype_atalkd, "zip_packet bad zip op from %u.%u",
751 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
756 if ( data + sizeof( struct atphdr ) > end ) {
757 LOG(log_info, logtype_atalkd, "zip atp malformed packet" );
760 memcpy( &ah, data, sizeof( struct atphdr ));
761 data += sizeof( struct atphdr );
762 if ( ah.atphd_ctrlinfo != ATP_TREQ ) {
763 LOG(log_info, logtype_atalkd, "zip atp bad control" );
766 ah.atphd_ctrlinfo = ATP_TRESP | ATP_EOM;
767 if ( ah.atphd_bitmap != 1 ) {
768 LOG(log_error, logtype_atalkd, "zip atp bad bitmap" );
775 memcpy( &index, data, sizeof( u_short ));
776 data += sizeof( u_short );
777 index = ntohs( index );
779 LOG(log_info, logtype_atalkd, "zip atp malformed packet" );
784 end = data + sizeof( packet );
785 *data++ = DDPTYPE_ATP;
786 memcpy( data, &ah, sizeof( struct atphdr ));
787 data += sizeof( struct atphdr );
788 lastflag = data++; /* mark and space for last flag */
790 nzones = data; /* mark and space for zone count */
791 data += sizeof( u_short );
794 case ZIPOP_GETMYZONE :
796 LOG(log_info, logtype_atalkd, "zip atp gmz bad index" );
800 if ( iface->i_flags & IFACE_LOOPBACK ) {
801 iface = interfaces->i_next; /* first interface */
802 } else if ( ntohs( iface->i_rt->rt_firstnet ) >
803 ntohs( from->sat_addr.s_net ) ||
804 ntohs( iface->i_rt->rt_lastnet ) <
805 ntohs( from->sat_addr.s_net )) {
809 if ( iface->i_rt->rt_zt == 0 ) {
812 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
813 if ( data + 1 + zt->zt_len > end ) {
814 LOG(log_info, logtype_atalkd, "zip atp gmz reply too long" );
817 *data++ = zt->zt_len;
818 memcpy( data, zt->zt_name, zt->zt_len );
825 case ZIPOP_GETZONELIST :
826 for ( zt = ziptab; zt && ( index > 1 ); zt = zt->zt_next, index-- )
828 for ( nz = 0; zt; zt = zt->zt_next, nz++ ) {
829 if ( data + 1 + zt->zt_len > end ) {
832 *data++ = zt->zt_len;
833 memcpy( data, zt->zt_name, zt->zt_len );
837 *lastflag = ( zt == 0 ); /* Too clever? */
840 case ZIPOP_GETLOCALZONES :
841 if ( iface->i_flags & IFACE_LOOPBACK ) {
842 iface = interfaces->i_next; /* first interface */
843 } else if ( ntohs( iface->i_rt->rt_firstnet ) >
844 ntohs( from->sat_addr.s_net ) ||
845 ntohs( iface->i_rt->rt_lastnet ) <
846 ntohs( from->sat_addr.s_net )) {
850 for ( l = iface->i_rt->rt_zt; l && ( index > 1 );
851 l = l->l_next, index-- )
853 for ( nz = 0; l; l = l->l_next, nz++ ) {
854 zt = (struct ziptab *)l->l_data;
855 if ( data + 1 + zt->zt_len > end ) {
858 *data++ = zt->zt_len;
859 memcpy( data, zt->zt_name, zt->zt_len );
863 *lastflag = ( l == 0 );
867 LOG(log_info, logtype_atalkd, "zip atp bad option" );
874 memcpy( nzones, &nz, sizeof( u_short ));
875 if ( sendto( ap->ap_fd, packet, data - packet, 0,
876 (struct sockaddr *)from,
877 sizeof( struct sockaddr_at )) < 0 ) {
878 LOG(log_error, logtype_atalkd, "zip atp sendto %u.%u: %s",
879 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
887 LOG(log_info, logtype_atalkd, "zip_packet bad ddp type from %u.%u",
888 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
895 int zip_getnetinfo(struct interface *iface)
899 struct sockaddr_at sat;
900 char *data, packet[ 40 ];
903 LOG(log_info, logtype_atalkd, "zip_getnetinfo for %s", iface->i_name );
905 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
906 if ( ap->ap_packet == zip_packet ) {
911 LOG(log_error, logtype_atalkd, "zip_getnetinfo can't find zip socket!" );
917 *data++ = DDPTYPE_ZIP;
919 zh.zh_op = ZIPOP_GNI;
921 memcpy( data, &zh, sizeof( struct ziphdr ));
922 data += sizeof( struct ziphdr );
924 memcpy( data, &net, sizeof( u_short ));
925 data += sizeof( u_short );
926 memcpy( data, &net, sizeof( u_short ));
927 data += sizeof( u_short );
930 * Set our requesting zone to NULL, so the response will contain
936 sat.sat_len = sizeof( struct sockaddr_at );
938 sat.sat_family = AF_APPLETALK;
939 sat.sat_addr.s_net = 0;
940 sat.sat_addr.s_node = ATADDR_BCAST;
941 sat.sat_port = ap->ap_port;
943 if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
944 sizeof( struct sockaddr_at )) < 0 ) {
945 LOG(log_error, logtype_atalkd, "zip_getnetinfo sendto: %s", strerror(errno) );
951 struct ziptab *newzt(const int len, const char *name)
955 if (( zt = (struct ziptab *)calloc(1, sizeof( struct ziptab ))) == NULL ) {
960 if (( zt->zt_name = (char *)malloc( len )) == NULL ) {
965 memcpy( zt->zt_name, name, len );
971 * Insert at the end. Return 1 if a mapping already exists, 0 otherwise.
974 static int add_list(struct list **head, void *data)
978 for ( l = *head; l; l = l->l_next ) {
979 if ( l->l_data == data ) {
983 if (( l = (struct list *)malloc( sizeof( struct list ))) == NULL ) {
984 LOG(log_error, logtype_atalkd, "add_list malloc: %s", strerror(errno) );
990 if ( *head == NULL ) {
994 /* find end of list */
995 for ( l2 = *head; l2->l_next; l2 = l2->l_next )
1003 int addzone(struct rtmptab *rt, int len, char *zone)
1008 for ( zt = ziptab; zt; zt = zt->zt_next ) {
1009 if ( zt->zt_len == len &&
1010 strndiacasecmp( zt->zt_name, zone, len ) == 0 ) {
1015 if (( zt = newzt( len, zone )) == NULL ) {
1016 LOG(log_error, logtype_atalkd, "addzone newzt: %s", strerror(errno) );
1019 if ( ziptab == NULL ) {
1023 zt->zt_prev = ziplast;
1024 ziplast->zt_next = zt;
1029 if ((cc = add_list( &zt->zt_rt, rt )) < 0)
1035 if ((cc = add_list( &rt->rt_zt, zt )) < 0 )
1040 LOG(log_error, logtype_atalkd, "addzone corrupted route/zone mapping" );
1044 * We get the repeat for local nets which have zone information
1045 * already: we ask anyway, just to make sure.
1051 LOG(log_error, logtype_atalkd, "addzone corrupted zone/route mapping" );