2 * $Id: nbp.c,v 1.11 2005-04-28 20:49:46 bfernhomberg 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 <atalk/logger.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
22 #include <net/route.h>
25 #include <netatalk/at.h>
26 #include <atalk/ddp.h>
27 #include <atalk/atp.h>
28 #include <atalk/nbp.h>
29 #include <atalk/util.h>
32 #include <sys/sockio.h>
36 #include "interface.h"
42 #include "multicast.h"
44 extern int transition;
46 struct nbptab *nbptab = NULL;
49 void nbp_ack( fd, nh_op, nh_id, to )
53 struct sockaddr_at *to;
56 char *data, packet[ SZ_NBPHDR + 1 ];
62 *data++ = DDPTYPE_NBP;
63 memcpy( data, &nh, SZ_NBPHDR );
65 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
66 sizeof( struct sockaddr_at )) < 0 ) {
67 LOG(log_error, logtype_atalkd, "sendto: %s", strerror(errno) );
71 int nbp_packet( ap, from, data, len )
73 struct sockaddr_at *from;
80 struct sockaddr_at sat;
82 struct ziptab *zt=NULL;
83 struct interface *iface;
86 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
87 int n, i, cc, locallkup;
92 LOG(log_info, logtype_atalkd, "nbp_packet malformed packet" );
95 if ( *data++ != DDPTYPE_NBP ) {
96 LOG(log_info, logtype_atalkd, "nbp_packet bad ddp type" );
100 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
101 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
104 memcpy( &nh, data, SZ_NBPHDR );
105 nbpop = data; /* remember for fwd and brrq */
107 if ( nh.nh_cnt != 1 ) {
108 LOG(log_info, logtype_atalkd, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
113 memcpy( &nt, data, SZ_NBPTUPLE );
116 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
118 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
120 nn.nn_sat.sat_family = AF_APPLETALK;
121 nn.nn_sat.sat_addr.s_net = nt.nt_net;
122 nn.nn_sat.sat_addr.s_node = nt.nt_node;
123 nn.nn_sat.sat_port = nt.nt_port;
126 tmplen = (u_char) *data;
127 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
128 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
131 nn.nn_objlen = tmplen;
133 memcpy( nn.nn_obj, data, nn.nn_objlen );
134 data += nn.nn_objlen;
137 tmplen = (u_char) *data;
138 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
139 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
142 nn.nn_typelen = tmplen;
144 memcpy( nn.nn_type, data, nn.nn_typelen );
145 data += nn.nn_typelen;
148 tmplen = (u_char) *data;
149 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
150 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
153 zonep = data; /* remember for fwd */
154 nn.nn_zonelen = tmplen;
156 memcpy( nn.nn_zone, data, nn.nn_zonelen );
157 data += nn.nn_zonelen;
160 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
165 switch ( nh.nh_op ) {
169 * Find the ziptab entry for the zone we're trying to register in.
171 if ( nn.nn_zonelen == 0 ||
172 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
173 if ( interfaces->i_next->i_rt->rt_zt ) {
174 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
179 for ( zt = ziptab; zt; zt = zt->zt_next ) {
180 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
181 nn.nn_zone, zt->zt_len ) == 0 ) {
186 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
192 * Observe that we don't have to do any local-zone verification
193 * if the zone aleady has a multicast address set.
195 if ( zt != 0 && zt->zt_bcast == 0 ) {
197 * Check if zone is associated with any of our local interfaces.
199 for ( iface = interfaces; iface; iface = iface->i_next ) {
200 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
201 if ( zt == (struct ziptab *)l->l_data ) {
210 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
214 /* calculate and save multicast address */
215 if (zone_bcast(zt) < 0) {
216 LOG(log_error, logtype_atalkd, "nbp_packet: zone_bcast");
220 for ( iface = interfaces; iface; iface = iface->i_next ) {
221 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
224 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
225 if ( zt == (struct ziptab *)l->l_data ) {
227 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
228 LOG(log_error, logtype_atalkd, "nbp_packet: addmulti: %s",
237 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
239 LOG(log_error, logtype_atalkd, "nbp_packet: malloc: %s", strerror(errno) );
242 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
243 ntab->nt_iface = ap->ap_iface;
244 ntab->nt_next = nbptab;
247 nbptab->nt_prev = ntab;
251 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
255 /* deal with local zone info */
256 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
257 ( nn.nn_zonelen == 0 )) {
259 if ( interfaces->i_next->i_rt->rt_zt ) {
260 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
266 /* remove from our data, perhaps removing a multicast address */
267 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
268 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
269 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
273 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
274 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
279 * I *think* we really do check the zone, here.
281 * i changed it to better handle local zone cases as well.
285 /* match local zones */
287 /* ntab is also local zone */
288 if (( ntab->nt_nve.nn_zonelen == 1 &&
289 *ntab->nt_nve.nn_zone == '*' ) ||
290 (ntab->nt_nve.nn_zonelen == 0))
293 /* ntab is default zone */
294 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
295 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
301 /* match particular zone */
302 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
303 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
304 nn.nn_zonelen ) == 0)) {
309 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
313 if ( ntab->nt_next != 0 ) {
314 ntab->nt_next->nt_prev = ntab->nt_prev;
316 if ( ntab->nt_prev != 0 ) {
317 ntab->nt_prev->nt_next = ntab->nt_next;
319 if ( ntab == nbptab ) {
320 nbptab = ntab->nt_next;
324 * Check for another nbptab entry with the same zone. If
325 * there isn't one, find the ziptab entry for the zone and
326 * remove the multicast address from the appropriate interfaces.
330 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
335 * Couple of things: 1. Unless we have the -t flag (which is sort
336 * of a misnomer, since you need it if you're doing any phase 1
337 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
338 * and we know what the sender meant by '*', we copy the real
339 * zone into the packet.
341 if ( nn.nn_zonelen == 0 ||
342 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
343 iface = ap->ap_iface;
344 if ( iface && iface->i_rt->rt_zt ) {
345 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
346 } else if ( interfaces->i_next->i_rt->rt_zt ) {
347 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
353 * Copy zone into packet. Note that we're changing len, data, and
354 * nbpop. Later, we'll use ( data - len ) to mean the beginning
358 memcpy( packet, data - len, len );
359 nbpop = packet + ( len - ( data - nbpop ));
360 data = packet + ( len - ( data - zonep ));
361 *data++ = zt->zt_len;
362 memcpy( data, zt->zt_name, zt->zt_len );
367 for ( zt = ziptab; zt; zt = zt->zt_next ) {
368 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
369 nn.nn_zone, zt->zt_len ) == 0 ) {
374 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
380 * If we've got no zones, send out LKUP on the local net.
381 * Otherwise, look through the zone table.
385 sat.sat_len = sizeof( struct sockaddr_at );
387 sat.sat_family = AF_APPLETALK;
388 sat.sat_port = ap->ap_port;
390 nh.nh_op = NBPOP_LKUP;
391 memcpy( nbpop, &nh, SZ_NBPHDR );
392 sat.sat_addr.s_net = 0; /* XXX */
393 sat.sat_addr.s_node = ATADDR_BCAST;
395 /* Find the first non-loopback ap */
396 for ( iface = interfaces; iface; iface = iface->i_next ) {
397 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
398 (iface == ap->ap_iface ||
399 (iface->i_flags & IFACE_ISROUTER))) {
406 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
407 if ( ap->ap_packet == nbp_packet ) {
412 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
413 sizeof( struct sockaddr_at )) < 0 ) {
414 LOG(log_error, logtype_atalkd, "nbp brrq sendto: %s", strerror(errno) );
420 sat.sat_len = sizeof( struct sockaddr_at );
422 sat.sat_family = AF_APPLETALK;
423 sat.sat_port = ap->ap_port;
424 for ( l = zt->zt_rt; l; l = l->l_next ) {
425 rtmp = (struct rtmptab *)l->l_data;
427 if ( rtmp->rt_gate == 0 ) {
428 for ( iface = interfaces; iface;
429 iface = iface->i_next ) {
430 if ( iface->i_rt == rtmp ) {
435 LOG(log_error, logtype_atalkd, "nbp_packet: \
436 Can't find route's interface!" );
441 ap = rtmp->rt_gate->g_iface->i_ports;
443 for ( ; ap; ap = ap->ap_next ) {
444 if ( ap->ap_packet == nbp_packet ) {
449 LOG(log_error, logtype_atalkd, "nbp_packet: Can't find port!" );
454 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
455 if ( rtmp->rt_gate == 0 ) {
458 nh.nh_op = NBPOP_LKUP;
459 memcpy( nbpop, &nh, SZ_NBPHDR );
460 sat.sat_addr.s_net = rtmp->rt_firstnet;
461 sat.sat_addr.s_node = ATADDR_BCAST;
463 if ( rtmp->rt_gate == 0 ) {
464 nh.nh_op = NBPOP_LKUP;
465 memcpy( nbpop, &nh, SZ_NBPHDR );
466 sat.sat_addr.s_net = 0;
467 sat.sat_addr.s_node = ATADDR_BCAST;
470 nh.nh_op = NBPOP_FWD;
471 memcpy( nbpop, &nh, SZ_NBPHDR );
472 sat.sat_addr.s_net = rtmp->rt_firstnet;
473 sat.sat_addr.s_node = 0;
477 if ( sendto( ap->ap_fd, data - len, len, 0,
478 (struct sockaddr *)&sat,
479 sizeof( struct sockaddr_at )) < 0 ) {
480 LOG(log_error, logtype_atalkd, "nbp brrq sendto %u.%u: %s",
481 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node,
494 /* send lkup on net. we need to make sure we're a router. */
495 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
496 nh.nh_op = NBPOP_LKUP;
497 memcpy( nbpop, &nh, SZ_NBPHDR );
498 from->sat_addr.s_net = 0;
499 from->sat_addr.s_node = ATADDR_BCAST;
500 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
501 sizeof( struct sockaddr_at )) < 0 ) {
502 LOG(log_error, logtype_atalkd, "nbp fwd sendto %u.%u: %s",
503 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
511 /* search our data */
513 data = packet + 1 + SZ_NBPHDR;
514 end = packet + sizeof( packet );
516 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
517 /* don't send out entries if we don't want to route. */
518 if ((ap->ap_iface != ntab->nt_iface) &&
519 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
523 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
524 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
525 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
531 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
532 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
533 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
539 if ( nn.nn_zonelen != 0 &&
540 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
541 if ( ntab->nt_nve.nn_zonelen == 0 ||
542 ( ntab->nt_nve.nn_zonelen == 1 &&
543 *ntab->nt_nve.nn_zone == '*' )) {
544 if ( interfaces->i_next->i_rt->rt_zt ) {
545 zt = (struct ziptab *)interfaces->i_next->i_rt->
547 if ( zt->zt_len != nn.nn_zonelen ||
548 strndiacasecmp( zt->zt_name, nn.nn_zone,
554 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
555 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
563 * Another tuple won't fit. Send what we've already
564 * got, and start the next packet.
566 if ( n > 14 || data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
567 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
568 nh.nh_op = NBPOP_LKUPREPLY;
572 *data++ = DDPTYPE_NBP;
573 memcpy( data, &nh, SZ_NBPHDR );
575 if ( sendto( ap->ap_fd, packet, cc, 0,
576 (struct sockaddr *)&nn.nn_sat,
577 sizeof( struct sockaddr_at )) < 0 ) {
578 LOG(log_error, logtype_atalkd, "nbp lkup sendto %u.%u: %s",
579 ntohs( nn.nn_sat.sat_addr.s_net ),
580 nn.nn_sat.sat_addr.s_node,
586 data = packet + 1 + SZ_NBPHDR;
587 end = packet + sizeof( packet );
590 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
591 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
592 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
594 * Right now, we'll just give each name a unique enum. In
595 * the future, we might need to actually assign and save
596 * an enum, based on the associated address. For the moment,
597 * the enums will be unique and constant, since the order
602 memcpy( data, &nt, SZ_NBPTUPLE );
605 *data++ = ntab->nt_nve.nn_objlen;
606 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
607 data += ntab->nt_nve.nn_objlen;
609 *data++ = ntab->nt_nve.nn_typelen;
610 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
611 data += ntab->nt_nve.nn_typelen;
614 * Macs won't see something with a zone of 0 length. We
615 * will always return '*' instead. Perhaps we should
616 * unconditionally return the real zone?
618 if ( ntab->nt_nve.nn_zonelen ) {
619 *data++ = ntab->nt_nve.nn_zonelen;
620 memcpy( data, ntab->nt_nve.nn_zone, ntab->nt_nve.nn_zonelen );
621 data += ntab->nt_nve.nn_zonelen;
631 nh.nh_op = NBPOP_LKUPREPLY;
635 *data++ = DDPTYPE_NBP;
636 memcpy( data, &nh, SZ_NBPHDR );
638 if ( sendto( ap->ap_fd, packet, cc, 0,
639 (struct sockaddr *)&nn.nn_sat,
640 sizeof( struct sockaddr_at )) < 0 ) {
641 LOG(log_error, logtype_atalkd, "nbp lkup sendto %u.%u: %s",
642 ntohs( nn.nn_sat.sat_addr.s_net ),
643 nn.nn_sat.sat_addr.s_node,
651 LOG(log_info, logtype_atalkd, "nbp_packet: bad op (%d)", nh.nh_op );