2 * $Id: nbp.c,v 1.12 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 <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( int fd, int nh_op, int nh_id, struct sockaddr_at *to)
52 char *data, packet[ SZ_NBPHDR + 1 ];
58 *data++ = DDPTYPE_NBP;
59 memcpy( data, &nh, SZ_NBPHDR );
61 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
62 sizeof( struct sockaddr_at )) < 0 ) {
63 LOG(log_error, logtype_atalkd, "sendto: %s", strerror(errno) );
67 int nbp_packet(struct atport *ap, struct sockaddr_at *from, char *data, int len)
72 struct sockaddr_at sat;
74 struct ziptab *zt=NULL;
75 struct interface *iface;
78 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
79 int n, i, cc, locallkup;
84 LOG(log_info, logtype_atalkd, "nbp_packet malformed packet" );
87 if ( *data++ != DDPTYPE_NBP ) {
88 LOG(log_info, logtype_atalkd, "nbp_packet bad ddp type" );
92 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
93 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
96 memcpy( &nh, data, SZ_NBPHDR );
97 nbpop = data; /* remember for fwd and brrq */
99 if ( nh.nh_cnt != 1 ) {
100 LOG(log_info, logtype_atalkd, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
105 memcpy( &nt, data, SZ_NBPTUPLE );
108 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
110 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
112 nn.nn_sat.sat_family = AF_APPLETALK;
113 nn.nn_sat.sat_addr.s_net = nt.nt_net;
114 nn.nn_sat.sat_addr.s_node = nt.nt_node;
115 nn.nn_sat.sat_port = nt.nt_port;
118 tmplen = (u_char) *data;
119 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
120 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
123 nn.nn_objlen = tmplen;
125 memcpy( nn.nn_obj, data, nn.nn_objlen );
126 data += nn.nn_objlen;
129 tmplen = (u_char) *data;
130 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
131 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
134 nn.nn_typelen = tmplen;
136 memcpy( nn.nn_type, data, nn.nn_typelen );
137 data += nn.nn_typelen;
140 tmplen = (u_char) *data;
141 if ( data >= end || tmplen > 32 || data + tmplen > end ) {
142 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
145 zonep = data; /* remember for fwd */
146 nn.nn_zonelen = tmplen;
148 memcpy( nn.nn_zone, data, nn.nn_zonelen );
149 data += nn.nn_zonelen;
152 LOG(log_info, logtype_atalkd, "nbp_packet: malformed packet" );
157 switch ( nh.nh_op ) {
161 * Find the ziptab entry for the zone we're trying to register in.
163 if ( nn.nn_zonelen == 0 ||
164 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
165 if ( interfaces->i_next->i_rt->rt_zt ) {
166 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
171 for ( zt = ziptab; zt; zt = zt->zt_next ) {
172 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
173 nn.nn_zone, zt->zt_len ) == 0 ) {
178 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
184 * Observe that we don't have to do any local-zone verification
185 * if the zone aleady has a multicast address set.
187 if ( zt != 0 && zt->zt_bcast == 0 ) {
189 * Check if zone is associated with any of our local interfaces.
191 for ( iface = interfaces; iface; iface = iface->i_next ) {
192 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
193 if ( zt == (struct ziptab *)l->l_data ) {
202 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
206 /* calculate and save multicast address */
207 if (zone_bcast(zt) < 0) {
208 LOG(log_error, logtype_atalkd, "nbp_packet: zone_bcast");
212 for ( iface = interfaces; iface; iface = iface->i_next ) {
213 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
216 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
217 if ( zt == (struct ziptab *)l->l_data ) {
219 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
220 LOG(log_error, logtype_atalkd, "nbp_packet: addmulti: %s",
229 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
231 LOG(log_error, logtype_atalkd, "nbp_packet: malloc: %s", strerror(errno) );
234 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
235 ntab->nt_iface = ap->ap_iface;
236 ntab->nt_next = nbptab;
239 nbptab->nt_prev = ntab;
243 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
247 /* deal with local zone info */
248 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
249 ( nn.nn_zonelen == 0 )) {
251 if ( interfaces->i_next->i_rt->rt_zt ) {
252 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
258 /* remove from our data, perhaps removing a multicast address */
259 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
260 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
261 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
265 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
266 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
271 * I *think* we really do check the zone, here.
273 * i changed it to better handle local zone cases as well.
277 /* match local zones */
279 /* ntab is also local zone */
280 if (( ntab->nt_nve.nn_zonelen == 1 &&
281 *ntab->nt_nve.nn_zone == '*' ) ||
282 (ntab->nt_nve.nn_zonelen == 0))
285 /* ntab is default zone */
286 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
287 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
293 /* match particular zone */
294 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
295 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
296 nn.nn_zonelen ) == 0)) {
301 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
305 if ( ntab->nt_next != 0 ) {
306 ntab->nt_next->nt_prev = ntab->nt_prev;
308 if ( ntab->nt_prev != 0 ) {
309 ntab->nt_prev->nt_next = ntab->nt_next;
311 if ( ntab == nbptab ) {
312 nbptab = ntab->nt_next;
316 * Check for another nbptab entry with the same zone. If
317 * there isn't one, find the ziptab entry for the zone and
318 * remove the multicast address from the appropriate interfaces.
322 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
327 * Couple of things: 1. Unless we have the -t flag (which is sort
328 * of a misnomer, since you need it if you're doing any phase 1
329 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
330 * and we know what the sender meant by '*', we copy the real
331 * zone into the packet.
333 if ( nn.nn_zonelen == 0 ||
334 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
335 iface = ap->ap_iface;
336 if ( iface && iface->i_rt->rt_zt ) {
337 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
338 } else if ( interfaces->i_next->i_rt->rt_zt ) {
339 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
345 * Copy zone into packet. Note that we're changing len, data, and
346 * nbpop. Later, we'll use ( data - len ) to mean the beginning
350 memcpy( packet, data - len, len );
351 nbpop = packet + ( len - ( data - nbpop ));
352 data = packet + ( len - ( data - zonep ));
353 *data++ = zt->zt_len;
354 memcpy( data, zt->zt_name, zt->zt_len );
359 for ( zt = ziptab; zt; zt = zt->zt_next ) {
360 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
361 nn.nn_zone, zt->zt_len ) == 0 ) {
366 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
372 * If we've got no zones, send out LKUP on the local net.
373 * Otherwise, look through the zone table.
377 sat.sat_len = sizeof( struct sockaddr_at );
379 sat.sat_family = AF_APPLETALK;
380 sat.sat_port = ap->ap_port;
382 nh.nh_op = NBPOP_LKUP;
383 memcpy( nbpop, &nh, SZ_NBPHDR );
384 sat.sat_addr.s_net = 0; /* XXX */
385 sat.sat_addr.s_node = ATADDR_BCAST;
387 /* Find the first non-loopback ap */
388 for ( iface = interfaces; iface; iface = iface->i_next ) {
389 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
390 (iface == ap->ap_iface ||
391 (iface->i_flags & IFACE_ISROUTER))) {
398 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
399 if ( ap->ap_packet == nbp_packet ) {
404 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
405 sizeof( struct sockaddr_at )) < 0 ) {
406 LOG(log_error, logtype_atalkd, "nbp brrq sendto: %s", strerror(errno) );
412 sat.sat_len = sizeof( struct sockaddr_at );
414 sat.sat_family = AF_APPLETALK;
415 sat.sat_port = ap->ap_port;
416 for ( l = zt->zt_rt; l; l = l->l_next ) {
417 rtmp = (struct rtmptab *)l->l_data;
419 if ( rtmp->rt_gate == 0 ) {
420 for ( iface = interfaces; iface;
421 iface = iface->i_next ) {
422 if ( iface->i_rt == rtmp ) {
427 LOG(log_error, logtype_atalkd, "nbp_packet: \
428 Can't find route's interface!" );
433 ap = rtmp->rt_gate->g_iface->i_ports;
435 for ( ; ap; ap = ap->ap_next ) {
436 if ( ap->ap_packet == nbp_packet ) {
441 LOG(log_error, logtype_atalkd, "nbp_packet: Can't find port!" );
446 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
447 if ( rtmp->rt_gate == 0 ) {
450 nh.nh_op = NBPOP_LKUP;
451 memcpy( nbpop, &nh, SZ_NBPHDR );
452 sat.sat_addr.s_net = rtmp->rt_firstnet;
453 sat.sat_addr.s_node = ATADDR_BCAST;
455 if ( rtmp->rt_gate == 0 ) {
456 nh.nh_op = NBPOP_LKUP;
457 memcpy( nbpop, &nh, SZ_NBPHDR );
458 sat.sat_addr.s_net = 0;
459 sat.sat_addr.s_node = ATADDR_BCAST;
462 nh.nh_op = NBPOP_FWD;
463 memcpy( nbpop, &nh, SZ_NBPHDR );
464 sat.sat_addr.s_net = rtmp->rt_firstnet;
465 sat.sat_addr.s_node = 0;
469 if ( sendto( ap->ap_fd, data - len, len, 0,
470 (struct sockaddr *)&sat,
471 sizeof( struct sockaddr_at )) < 0 ) {
472 LOG(log_error, logtype_atalkd, "nbp brrq sendto %u.%u: %s",
473 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node,
486 /* send lkup on net. we need to make sure we're a router. */
487 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
488 nh.nh_op = NBPOP_LKUP;
489 memcpy( nbpop, &nh, SZ_NBPHDR );
490 from->sat_addr.s_net = 0;
491 from->sat_addr.s_node = ATADDR_BCAST;
492 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
493 sizeof( struct sockaddr_at )) < 0 ) {
494 LOG(log_error, logtype_atalkd, "nbp fwd sendto %u.%u: %s",
495 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
503 /* search our data */
505 data = packet + 1 + SZ_NBPHDR;
506 end = packet + sizeof( packet );
508 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
509 /* don't send out entries if we don't want to route. */
510 if ((ap->ap_iface != ntab->nt_iface) &&
511 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
515 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
516 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
517 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
523 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
524 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
525 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
531 if ( nn.nn_zonelen != 0 &&
532 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
533 if ( ntab->nt_nve.nn_zonelen == 0 ||
534 ( ntab->nt_nve.nn_zonelen == 1 &&
535 *ntab->nt_nve.nn_zone == '*' )) {
536 if ( interfaces->i_next->i_rt->rt_zt ) {
537 zt = (struct ziptab *)interfaces->i_next->i_rt->
539 if ( zt->zt_len != nn.nn_zonelen ||
540 strndiacasecmp( zt->zt_name, nn.nn_zone,
546 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
547 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
555 * Another tuple won't fit. Send what we've already
556 * got, and start the next packet.
558 if ( n > 14 || data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
559 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
560 nh.nh_op = NBPOP_LKUPREPLY;
564 *data++ = DDPTYPE_NBP;
565 memcpy( data, &nh, SZ_NBPHDR );
567 if ( sendto( ap->ap_fd, packet, cc, 0,
568 (struct sockaddr *)&nn.nn_sat,
569 sizeof( struct sockaddr_at )) < 0 ) {
570 LOG(log_error, logtype_atalkd, "nbp lkup sendto %u.%u: %s",
571 ntohs( nn.nn_sat.sat_addr.s_net ),
572 nn.nn_sat.sat_addr.s_node,
578 data = packet + 1 + SZ_NBPHDR;
579 end = packet + sizeof( packet );
582 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
583 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
584 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
586 * Right now, we'll just give each name a unique enum. In
587 * the future, we might need to actually assign and save
588 * an enum, based on the associated address. For the moment,
589 * the enums will be unique and constant, since the order
594 memcpy( data, &nt, SZ_NBPTUPLE );
597 *data++ = ntab->nt_nve.nn_objlen;
598 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
599 data += ntab->nt_nve.nn_objlen;
601 *data++ = ntab->nt_nve.nn_typelen;
602 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
603 data += ntab->nt_nve.nn_typelen;
606 * Macs won't see something with a zone of 0 length. We
607 * will always return '*' instead. Perhaps we should
608 * unconditionally return the real zone?
610 if ( ntab->nt_nve.nn_zonelen ) {
611 *data++ = ntab->nt_nve.nn_zonelen;
612 memcpy( data, ntab->nt_nve.nn_zone, ntab->nt_nve.nn_zonelen );
613 data += ntab->nt_nve.nn_zonelen;
623 nh.nh_op = NBPOP_LKUPREPLY;
627 *data++ = DDPTYPE_NBP;
628 memcpy( data, &nh, SZ_NBPHDR );
630 if ( sendto( ap->ap_fd, packet, cc, 0,
631 (struct sockaddr *)&nn.nn_sat,
632 sizeof( struct sockaddr_at )) < 0 ) {
633 LOG(log_error, logtype_atalkd, "nbp lkup sendto %u.%u: %s",
634 ntohs( nn.nn_sat.sat_addr.s_net ),
635 nn.nn_sat.sat_addr.s_node,
643 LOG(log_info, logtype_atalkd, "nbp_packet: bad op (%d)", nh.nh_op );