2 * $Id: nbp.c,v 1.3 2001-06-25 20:13:45 rufustfirefly Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
14 #include <sys/syslog.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
20 #include <netatalk/at.h>
21 #include <atalk/ddp.h>
22 #include <atalk/atp.h>
23 #include <atalk/nbp.h>
24 #include <atalk/util.h>
27 #include <sys/sockio.h>
31 #include "interface.h"
37 #include "multicast.h"
39 extern int transition;
41 struct nbptab *nbptab = NULL;
44 void nbp_ack( fd, nh_op, nh_id, to )
48 struct sockaddr_at *to;
51 char *data, packet[ SZ_NBPHDR + 1 ];
57 *data++ = DDPTYPE_NBP;
58 bcopy( &nh, data, SZ_NBPHDR );
60 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
61 sizeof( struct sockaddr_at )) < 0 ) {
62 syslog( LOG_ERR, "sendto: %m" );
66 int nbp_packet( ap, from, data, len )
68 struct sockaddr_at *from;
75 struct sockaddr_at sat;
78 struct interface *iface;
81 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
82 int n, i, cc, locallkup;
86 syslog( LOG_INFO, "nbp_packet malformed packet" );
89 if ( *data++ != DDPTYPE_NBP ) {
90 syslog( LOG_INFO, "nbp_packet bad ddp type" );
94 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
95 syslog( LOG_INFO, "nbp_packet: malformed packet" );
98 memcpy( &nh, data, SZ_NBPHDR );
99 nbpop = data; /* remember for fwd and brrq */
101 if ( nh.nh_cnt != 1 ) {
102 syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
107 memcpy( &nt, data, SZ_NBPTUPLE );
110 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
112 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
114 nn.nn_sat.sat_family = AF_APPLETALK;
115 nn.nn_sat.sat_addr.s_net = nt.nt_net;
116 nn.nn_sat.sat_addr.s_node = nt.nt_node;
117 nn.nn_sat.sat_port = nt.nt_port;
120 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
121 syslog( LOG_INFO, "nbp_packet: malformed packet" );
124 nn.nn_objlen = *data++;
125 memcpy( nn.nn_obj, data, nn.nn_objlen );
126 data += nn.nn_objlen;
129 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
130 syslog( LOG_INFO, "nbp_packet: malformed packet" );
133 nn.nn_typelen = *data++;
134 memcpy( nn.nn_type, data, nn.nn_typelen );
135 data += nn.nn_typelen;
138 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
139 syslog( LOG_INFO, "nbp_packet: malformed packet" );
142 zonep = data; /* remember for fwd */
143 nn.nn_zonelen = *data++;
144 memcpy( nn.nn_zone, data, nn.nn_zonelen );
145 data += nn.nn_zonelen;
148 syslog( LOG_INFO, "nbp_packet: malformed packet" );
153 switch ( nh.nh_op ) {
157 * Find the ziptab entry for the zone we're trying to register in.
159 if ( nn.nn_zonelen == 0 ||
160 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
161 if ( interfaces->i_next->i_rt->rt_zt ) {
162 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
167 for ( zt = ziptab; zt; zt = zt->zt_next ) {
168 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
169 nn.nn_zone, zt->zt_len ) == 0 ) {
174 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
180 * Observe that we don't have to do any local-zone verification
181 * if the zone aleady has a multicast address set.
183 if ( zt != 0 && zt->zt_bcast == 0 ) {
185 * Check if zone is associated with any of our local interfaces.
187 for ( iface = interfaces; iface; iface = iface->i_next ) {
188 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
189 if ( zt == (struct ziptab *)l->l_data ) {
198 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
202 /* calculate and save multicast address */
203 if (zone_bcast(zt) < 0) {
204 syslog(LOG_ERR, "nbp_packet: zone_bcast");
208 for ( iface = interfaces; iface; iface = iface->i_next ) {
209 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
212 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
213 if ( zt == (struct ziptab *)l->l_data ) {
215 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
216 syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
224 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
226 syslog( LOG_ERR, "nbp_packet: malloc: %m" );
229 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
230 ntab->nt_iface = ap->ap_iface;
231 ntab->nt_next = nbptab;
234 nbptab->nt_prev = ntab;
238 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
242 /* deal with local zone info */
243 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
244 ( nn.nn_zonelen == 0 )) {
246 if ( interfaces->i_next->i_rt->rt_zt ) {
247 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
253 /* remove from our data, perhaps removing a multicast address */
254 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
255 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
256 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
260 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
261 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
266 * I *think* we really do check the zone, here.
268 * i changed it to better handle local zone cases as well.
272 /* match local zones */
274 /* ntab is also local zone */
275 if (( ntab->nt_nve.nn_zonelen == 1 &&
276 *ntab->nt_nve.nn_zone == '*' ) ||
277 (ntab->nt_nve.nn_zonelen == 0))
280 /* ntab is default zone */
281 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
282 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
288 /* match particular zone */
289 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
290 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
291 nn.nn_zonelen ) == 0)) {
296 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
300 if ( ntab->nt_next != 0 ) {
301 ntab->nt_next->nt_prev = ntab->nt_prev;
303 if ( ntab->nt_prev != 0 ) {
304 ntab->nt_prev->nt_next = ntab->nt_next;
306 if ( ntab == nbptab ) {
307 nbptab = ntab->nt_next;
311 * Check for another nbptab entry with the same zone. If
312 * there isn't one, find the ziptab entry for the zone and
313 * remove the multicast address from the appropriate interfaces.
317 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
322 * Couple of things: 1. Unless we have the -t flag (which is sort
323 * of a misnomer, since you need it if you're doing any phase 1
324 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
325 * and we know what the sender meant by '*', we copy the real
326 * zone into the packet.
328 if ( nn.nn_zonelen == 0 ||
329 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
330 iface = ap->ap_iface;
331 if ( iface && iface->i_rt->rt_zt ) {
332 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
333 } else if ( interfaces->i_next->i_rt->rt_zt ) {
334 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
340 * Copy zone into packet. Note that we're changing len, data, and
341 * nbpop. Later, we'll use ( data - len ) to mean the beginning
345 memcpy( packet, data - len, len );
346 nbpop = packet + ( len - ( data - nbpop ));
347 data = packet + ( len - ( data - zonep ));
348 *data++ = zt->zt_len;
349 memcpy( data, zt->zt_name, zt->zt_len );
354 for ( zt = ziptab; zt; zt = zt->zt_next ) {
355 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
356 nn.nn_zone, zt->zt_len ) == 0 ) {
361 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
367 * If we've got no zones, send out LKUP on the local net.
368 * Otherwise, look through the zone table.
372 sat.sat_len = sizeof( struct sockaddr_at );
374 sat.sat_family = AF_APPLETALK;
375 sat.sat_port = ap->ap_port;
377 nh.nh_op = NBPOP_LKUP;
378 memcpy( nbpop, &nh, SZ_NBPHDR );
379 sat.sat_addr.s_net = 0; /* XXX */
380 sat.sat_addr.s_node = ATADDR_BCAST;
382 /* Find the first non-loopback ap */
383 for ( iface = interfaces; iface; iface = iface->i_next ) {
384 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
385 (iface == ap->ap_iface ||
386 (iface->i_flags & IFACE_ISROUTER))) {
393 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
394 if ( ap->ap_packet == nbp_packet ) {
399 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
400 sizeof( struct sockaddr_at )) < 0 ) {
401 syslog( LOG_ERR, "nbp brrq sendto: %m" );
407 sat.sat_len = sizeof( struct sockaddr_at );
409 sat.sat_family = AF_APPLETALK;
410 sat.sat_port = ap->ap_port;
411 for ( l = zt->zt_rt; l; l = l->l_next ) {
412 rtmp = (struct rtmptab *)l->l_data;
414 if ( rtmp->rt_gate == 0 ) {
415 for ( iface = interfaces; iface;
416 iface = iface->i_next ) {
417 if ( iface->i_rt == rtmp ) {
422 syslog( LOG_ERR, "nbp_packet: \
423 Can't find route's interface!" );
428 ap = rtmp->rt_gate->g_iface->i_ports;
430 for ( ; ap; ap = ap->ap_next ) {
431 if ( ap->ap_packet == nbp_packet ) {
436 syslog( LOG_ERR, "nbp_packet: Can't find port!" );
441 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
442 if ( rtmp->rt_gate == 0 ) {
445 nh.nh_op = NBPOP_LKUP;
446 bcopy( &nh, nbpop, SZ_NBPHDR );
447 sat.sat_addr.s_net = rtmp->rt_firstnet;
448 sat.sat_addr.s_node = ATADDR_BCAST;
450 if ( rtmp->rt_gate == 0 ) {
451 nh.nh_op = NBPOP_LKUP;
452 bcopy( &nh, nbpop, SZ_NBPHDR );
453 sat.sat_addr.s_net = 0;
454 sat.sat_addr.s_node = ATADDR_BCAST;
457 nh.nh_op = NBPOP_FWD;
458 bcopy( &nh, nbpop, SZ_NBPHDR );
459 sat.sat_addr.s_net = rtmp->rt_firstnet;
460 sat.sat_addr.s_node = 0;
464 if ( sendto( ap->ap_fd, data - len, len, 0,
465 (struct sockaddr *)&sat,
466 sizeof( struct sockaddr_at )) < 0 ) {
467 syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
468 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
480 /* send lkup on net. we need to make sure we're a router. */
481 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
482 nh.nh_op = NBPOP_LKUP;
483 bcopy( &nh, nbpop, SZ_NBPHDR );
484 from->sat_addr.s_net = 0;
485 from->sat_addr.s_node = ATADDR_BCAST;
486 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
487 sizeof( struct sockaddr_at )) < 0 ) {
488 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
489 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
496 /* search our data */
498 data = packet + 1 + SZ_NBPHDR;
499 end = packet + sizeof( packet );
501 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
502 /* don't send out entries if we don't want to route. */
503 if ((ap->ap_iface != ntab->nt_iface) &&
504 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
508 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
509 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
510 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
516 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
517 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
518 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
524 if ( nn.nn_zonelen != 0 &&
525 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
526 if ( ntab->nt_nve.nn_zonelen == 0 ||
527 ( ntab->nt_nve.nn_zonelen == 1 &&
528 *ntab->nt_nve.nn_zone == '*' )) {
529 if ( interfaces->i_next->i_rt->rt_zt ) {
530 zt = (struct ziptab *)interfaces->i_next->i_rt->
532 if ( zt->zt_len != nn.nn_zonelen ||
533 strndiacasecmp( zt->zt_name, nn.nn_zone,
539 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
540 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
548 * Another tuple won't fit. Send what we've already
549 * got, and start the next packet.
551 if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
552 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
553 nh.nh_op = NBPOP_LKUPREPLY;
557 *data++ = DDPTYPE_NBP;
558 bcopy( &nh, data, SZ_NBPHDR );
560 if ( sendto( ap->ap_fd, packet, cc, 0,
561 (struct sockaddr *)&nn.nn_sat,
562 sizeof( struct sockaddr_at )) < 0 ) {
563 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
564 ntohs( nn.nn_sat.sat_addr.s_net ),
565 nn.nn_sat.sat_addr.s_node );
570 data = packet + 1 + SZ_NBPHDR;
571 end = packet + sizeof( packet );
574 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
575 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
576 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
578 * Right now, we'll just give each name a unique enum. In
579 * the future, we might need to actually assign and save
580 * an enum, based on the associated address. For the moment,
581 * the enums will be unique and constant, since the order
586 memcpy( data, &nt, SZ_NBPTUPLE );
589 *data++ = ntab->nt_nve.nn_objlen;
590 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
591 data += ntab->nt_nve.nn_objlen;
593 *data++ = ntab->nt_nve.nn_typelen;
594 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
595 data += ntab->nt_nve.nn_typelen;
598 * Macs won't see something with a zone of 0 length. We
599 * will always return '*' instead. Perhaps we should
600 * unconditionally return the real zone?
602 if ( ntab->nt_nve.nn_zonelen ) {
603 *data++ = ntab->nt_nve.nn_zonelen;
604 bcopy( ntab->nt_nve.nn_zone, data, ntab->nt_nve.nn_zonelen );
605 data += ntab->nt_nve.nn_zonelen;
615 nh.nh_op = NBPOP_LKUPREPLY;
619 *data++ = DDPTYPE_NBP;
620 bcopy( &nh, data, SZ_NBPHDR );
622 if ( sendto( ap->ap_fd, packet, cc, 0,
623 (struct sockaddr *)&nn.nn_sat,
624 sizeof( struct sockaddr_at )) < 0 ) {
625 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
626 ntohs( nn.nn_sat.sat_addr.s_net ),
627 nn.nn_sat.sat_addr.s_node );
634 syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );