2 * $Id: nbp.c,v 1.6 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/syslog.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 syslog( LOG_ERR, "sendto: %s", strerror(errno) );
71 int nbp_packet( ap, from, data, len )
73 struct sockaddr_at *from;
80 struct sockaddr_at sat;
83 struct interface *iface;
86 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
87 int n, i, cc, locallkup;
91 syslog( LOG_INFO, "nbp_packet malformed packet" );
94 if ( *data++ != DDPTYPE_NBP ) {
95 syslog( LOG_INFO, "nbp_packet bad ddp type" );
99 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
100 syslog( LOG_INFO, "nbp_packet: malformed packet" );
103 memcpy( &nh, data, SZ_NBPHDR );
104 nbpop = data; /* remember for fwd and brrq */
106 if ( nh.nh_cnt != 1 ) {
107 syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
112 memcpy( &nt, data, SZ_NBPTUPLE );
115 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
117 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
119 nn.nn_sat.sat_family = AF_APPLETALK;
120 nn.nn_sat.sat_addr.s_net = nt.nt_net;
121 nn.nn_sat.sat_addr.s_node = nt.nt_node;
122 nn.nn_sat.sat_port = nt.nt_port;
125 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
126 syslog( LOG_INFO, "nbp_packet: malformed packet" );
129 nn.nn_objlen = *data++;
130 memcpy( nn.nn_obj, data, nn.nn_objlen );
131 data += nn.nn_objlen;
134 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
135 syslog( LOG_INFO, "nbp_packet: malformed packet" );
138 nn.nn_typelen = *data++;
139 memcpy( nn.nn_type, data, nn.nn_typelen );
140 data += nn.nn_typelen;
143 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
144 syslog( LOG_INFO, "nbp_packet: malformed packet" );
147 zonep = data; /* remember for fwd */
148 nn.nn_zonelen = *data++;
149 memcpy( nn.nn_zone, data, nn.nn_zonelen );
150 data += nn.nn_zonelen;
153 syslog( LOG_INFO, "nbp_packet: malformed packet" );
158 switch ( nh.nh_op ) {
162 * Find the ziptab entry for the zone we're trying to register in.
164 if ( nn.nn_zonelen == 0 ||
165 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
166 if ( interfaces->i_next->i_rt->rt_zt ) {
167 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
172 for ( zt = ziptab; zt; zt = zt->zt_next ) {
173 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
174 nn.nn_zone, zt->zt_len ) == 0 ) {
179 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
185 * Observe that we don't have to do any local-zone verification
186 * if the zone aleady has a multicast address set.
188 if ( zt != 0 && zt->zt_bcast == 0 ) {
190 * Check if zone is associated with any of our local interfaces.
192 for ( iface = interfaces; iface; iface = iface->i_next ) {
193 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
194 if ( zt == (struct ziptab *)l->l_data ) {
203 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
207 /* calculate and save multicast address */
208 if (zone_bcast(zt) < 0) {
209 syslog(LOG_ERR, "nbp_packet: zone_bcast");
213 for ( iface = interfaces; iface; iface = iface->i_next ) {
214 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
217 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
218 if ( zt == (struct ziptab *)l->l_data ) {
220 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
221 syslog( LOG_ERR, "nbp_packet: addmulti: %s",
230 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
232 syslog( LOG_ERR, "nbp_packet: malloc: %s", strerror(errno) );
235 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
236 ntab->nt_iface = ap->ap_iface;
237 ntab->nt_next = nbptab;
240 nbptab->nt_prev = ntab;
244 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
248 /* deal with local zone info */
249 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
250 ( nn.nn_zonelen == 0 )) {
252 if ( interfaces->i_next->i_rt->rt_zt ) {
253 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
259 /* remove from our data, perhaps removing a multicast address */
260 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
261 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
262 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
266 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
267 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
272 * I *think* we really do check the zone, here.
274 * i changed it to better handle local zone cases as well.
278 /* match local zones */
280 /* ntab is also local zone */
281 if (( ntab->nt_nve.nn_zonelen == 1 &&
282 *ntab->nt_nve.nn_zone == '*' ) ||
283 (ntab->nt_nve.nn_zonelen == 0))
286 /* ntab is default zone */
287 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
288 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
294 /* match particular zone */
295 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
296 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
297 nn.nn_zonelen ) == 0)) {
302 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
306 if ( ntab->nt_next != 0 ) {
307 ntab->nt_next->nt_prev = ntab->nt_prev;
309 if ( ntab->nt_prev != 0 ) {
310 ntab->nt_prev->nt_next = ntab->nt_next;
312 if ( ntab == nbptab ) {
313 nbptab = ntab->nt_next;
317 * Check for another nbptab entry with the same zone. If
318 * there isn't one, find the ziptab entry for the zone and
319 * remove the multicast address from the appropriate interfaces.
323 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
328 * Couple of things: 1. Unless we have the -t flag (which is sort
329 * of a misnomer, since you need it if you're doing any phase 1
330 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
331 * and we know what the sender meant by '*', we copy the real
332 * zone into the packet.
334 if ( nn.nn_zonelen == 0 ||
335 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
336 iface = ap->ap_iface;
337 if ( iface && iface->i_rt->rt_zt ) {
338 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
339 } else if ( interfaces->i_next->i_rt->rt_zt ) {
340 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
346 * Copy zone into packet. Note that we're changing len, data, and
347 * nbpop. Later, we'll use ( data - len ) to mean the beginning
351 memcpy( packet, data - len, len );
352 nbpop = packet + ( len - ( data - nbpop ));
353 data = packet + ( len - ( data - zonep ));
354 *data++ = zt->zt_len;
355 memcpy( data, zt->zt_name, zt->zt_len );
360 for ( zt = ziptab; zt; zt = zt->zt_next ) {
361 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
362 nn.nn_zone, zt->zt_len ) == 0 ) {
367 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
373 * If we've got no zones, send out LKUP on the local net.
374 * Otherwise, look through the zone table.
378 sat.sat_len = sizeof( struct sockaddr_at );
380 sat.sat_family = AF_APPLETALK;
381 sat.sat_port = ap->ap_port;
383 nh.nh_op = NBPOP_LKUP;
384 memcpy( nbpop, &nh, SZ_NBPHDR );
385 sat.sat_addr.s_net = 0; /* XXX */
386 sat.sat_addr.s_node = ATADDR_BCAST;
388 /* Find the first non-loopback ap */
389 for ( iface = interfaces; iface; iface = iface->i_next ) {
390 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
391 (iface == ap->ap_iface ||
392 (iface->i_flags & IFACE_ISROUTER))) {
399 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
400 if ( ap->ap_packet == nbp_packet ) {
405 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
406 sizeof( struct sockaddr_at )) < 0 ) {
407 syslog( LOG_ERR, "nbp brrq sendto: %s", strerror(errno) );
413 sat.sat_len = sizeof( struct sockaddr_at );
415 sat.sat_family = AF_APPLETALK;
416 sat.sat_port = ap->ap_port;
417 for ( l = zt->zt_rt; l; l = l->l_next ) {
418 rtmp = (struct rtmptab *)l->l_data;
420 if ( rtmp->rt_gate == 0 ) {
421 for ( iface = interfaces; iface;
422 iface = iface->i_next ) {
423 if ( iface->i_rt == rtmp ) {
428 syslog( LOG_ERR, "nbp_packet: \
429 Can't find route's interface!" );
434 ap = rtmp->rt_gate->g_iface->i_ports;
436 for ( ; ap; ap = ap->ap_next ) {
437 if ( ap->ap_packet == nbp_packet ) {
442 syslog( LOG_ERR, "nbp_packet: Can't find port!" );
447 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
448 if ( rtmp->rt_gate == 0 ) {
451 nh.nh_op = NBPOP_LKUP;
452 memcpy( nbpop, &nh, SZ_NBPHDR );
453 sat.sat_addr.s_net = rtmp->rt_firstnet;
454 sat.sat_addr.s_node = ATADDR_BCAST;
456 if ( rtmp->rt_gate == 0 ) {
457 nh.nh_op = NBPOP_LKUP;
458 memcpy( nbpop, &nh, SZ_NBPHDR );
459 sat.sat_addr.s_net = 0;
460 sat.sat_addr.s_node = ATADDR_BCAST;
463 nh.nh_op = NBPOP_FWD;
464 memcpy( nbpop, &nh, SZ_NBPHDR );
465 sat.sat_addr.s_net = rtmp->rt_firstnet;
466 sat.sat_addr.s_node = 0;
470 if ( sendto( ap->ap_fd, data - len, len, 0,
471 (struct sockaddr *)&sat,
472 sizeof( struct sockaddr_at )) < 0 ) {
473 syslog( LOG_ERR, "nbp brrq sendto %u.%u: %s",
474 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node,
487 /* send lkup on net. we need to make sure we're a router. */
488 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
489 nh.nh_op = NBPOP_LKUP;
490 memcpy( nbpop, &nh, SZ_NBPHDR );
491 from->sat_addr.s_net = 0;
492 from->sat_addr.s_node = ATADDR_BCAST;
493 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
494 sizeof( struct sockaddr_at )) < 0 ) {
495 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %s",
496 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
504 /* search our data */
506 data = packet + 1 + SZ_NBPHDR;
507 end = packet + sizeof( packet );
509 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
510 /* don't send out entries if we don't want to route. */
511 if ((ap->ap_iface != ntab->nt_iface) &&
512 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
516 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
517 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
518 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
524 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
525 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
526 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
532 if ( nn.nn_zonelen != 0 &&
533 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
534 if ( ntab->nt_nve.nn_zonelen == 0 ||
535 ( ntab->nt_nve.nn_zonelen == 1 &&
536 *ntab->nt_nve.nn_zone == '*' )) {
537 if ( interfaces->i_next->i_rt->rt_zt ) {
538 zt = (struct ziptab *)interfaces->i_next->i_rt->
540 if ( zt->zt_len != nn.nn_zonelen ||
541 strndiacasecmp( zt->zt_name, nn.nn_zone,
547 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
548 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
556 * Another tuple won't fit. Send what we've already
557 * got, and start the next packet.
559 if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
560 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
561 nh.nh_op = NBPOP_LKUPREPLY;
565 *data++ = DDPTYPE_NBP;
566 memcpy( data, &nh, SZ_NBPHDR );
568 if ( sendto( ap->ap_fd, packet, cc, 0,
569 (struct sockaddr *)&nn.nn_sat,
570 sizeof( struct sockaddr_at )) < 0 ) {
571 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %s",
572 ntohs( nn.nn_sat.sat_addr.s_net ),
573 nn.nn_sat.sat_addr.s_node,
579 data = packet + 1 + SZ_NBPHDR;
580 end = packet + sizeof( packet );
583 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
584 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
585 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
587 * Right now, we'll just give each name a unique enum. In
588 * the future, we might need to actually assign and save
589 * an enum, based on the associated address. For the moment,
590 * the enums will be unique and constant, since the order
595 memcpy( data, &nt, SZ_NBPTUPLE );
598 *data++ = ntab->nt_nve.nn_objlen;
599 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
600 data += ntab->nt_nve.nn_objlen;
602 *data++ = ntab->nt_nve.nn_typelen;
603 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
604 data += ntab->nt_nve.nn_typelen;
607 * Macs won't see something with a zone of 0 length. We
608 * will always return '*' instead. Perhaps we should
609 * unconditionally return the real zone?
611 if ( ntab->nt_nve.nn_zonelen ) {
612 *data++ = ntab->nt_nve.nn_zonelen;
613 memcpy( data, ntab->nt_nve.nn_zone, ntab->nt_nve.nn_zonelen );
614 data += ntab->nt_nve.nn_zonelen;
624 nh.nh_op = NBPOP_LKUPREPLY;
628 *data++ = DDPTYPE_NBP;
629 memcpy( data, &nh, SZ_NBPHDR );
631 if ( sendto( ap->ap_fd, packet, cc, 0,
632 (struct sockaddr *)&nn.nn_sat,
633 sizeof( struct sockaddr_at )) < 0 ) {
634 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %s",
635 ntohs( nn.nn_sat.sat_addr.s_net ),
636 nn.nn_sat.sat_addr.s_node,
644 syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );