2 * $Id: nbp.c,v 1.5 2001-08-15 01:39:39 srittau 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>
21 #include <net/route.h>
24 #include <netatalk/at.h>
25 #include <atalk/ddp.h>
26 #include <atalk/atp.h>
27 #include <atalk/nbp.h>
28 #include <atalk/util.h>
31 #include <sys/sockio.h>
35 #include "interface.h"
41 #include "multicast.h"
43 extern int transition;
45 struct nbptab *nbptab = NULL;
48 void nbp_ack( fd, nh_op, nh_id, to )
52 struct sockaddr_at *to;
55 char *data, packet[ SZ_NBPHDR + 1 ];
61 *data++ = DDPTYPE_NBP;
62 memcpy( data, &nh, SZ_NBPHDR );
64 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
65 sizeof( struct sockaddr_at )) < 0 ) {
66 syslog( LOG_ERR, "sendto: %m" );
70 int nbp_packet( ap, from, data, len )
72 struct sockaddr_at *from;
79 struct sockaddr_at sat;
82 struct interface *iface;
85 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
86 int n, i, cc, locallkup;
90 syslog( LOG_INFO, "nbp_packet malformed packet" );
93 if ( *data++ != DDPTYPE_NBP ) {
94 syslog( LOG_INFO, "nbp_packet bad ddp type" );
98 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
99 syslog( LOG_INFO, "nbp_packet: malformed packet" );
102 memcpy( &nh, data, SZ_NBPHDR );
103 nbpop = data; /* remember for fwd and brrq */
105 if ( nh.nh_cnt != 1 ) {
106 syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
111 memcpy( &nt, data, SZ_NBPTUPLE );
114 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
116 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
118 nn.nn_sat.sat_family = AF_APPLETALK;
119 nn.nn_sat.sat_addr.s_net = nt.nt_net;
120 nn.nn_sat.sat_addr.s_node = nt.nt_node;
121 nn.nn_sat.sat_port = nt.nt_port;
124 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
125 syslog( LOG_INFO, "nbp_packet: malformed packet" );
128 nn.nn_objlen = *data++;
129 memcpy( nn.nn_obj, data, nn.nn_objlen );
130 data += nn.nn_objlen;
133 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
134 syslog( LOG_INFO, "nbp_packet: malformed packet" );
137 nn.nn_typelen = *data++;
138 memcpy( nn.nn_type, data, nn.nn_typelen );
139 data += nn.nn_typelen;
142 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
143 syslog( LOG_INFO, "nbp_packet: malformed packet" );
146 zonep = data; /* remember for fwd */
147 nn.nn_zonelen = *data++;
148 memcpy( nn.nn_zone, data, nn.nn_zonelen );
149 data += nn.nn_zonelen;
152 syslog( LOG_INFO, "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 syslog(LOG_ERR, "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 syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
228 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
230 syslog( LOG_ERR, "nbp_packet: malloc: %m" );
233 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
234 ntab->nt_iface = ap->ap_iface;
235 ntab->nt_next = nbptab;
238 nbptab->nt_prev = ntab;
242 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
246 /* deal with local zone info */
247 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
248 ( nn.nn_zonelen == 0 )) {
250 if ( interfaces->i_next->i_rt->rt_zt ) {
251 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
257 /* remove from our data, perhaps removing a multicast address */
258 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
259 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
260 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
264 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
265 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
270 * I *think* we really do check the zone, here.
272 * i changed it to better handle local zone cases as well.
276 /* match local zones */
278 /* ntab is also local zone */
279 if (( ntab->nt_nve.nn_zonelen == 1 &&
280 *ntab->nt_nve.nn_zone == '*' ) ||
281 (ntab->nt_nve.nn_zonelen == 0))
284 /* ntab is default zone */
285 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
286 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
292 /* match particular zone */
293 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
294 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
295 nn.nn_zonelen ) == 0)) {
300 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
304 if ( ntab->nt_next != 0 ) {
305 ntab->nt_next->nt_prev = ntab->nt_prev;
307 if ( ntab->nt_prev != 0 ) {
308 ntab->nt_prev->nt_next = ntab->nt_next;
310 if ( ntab == nbptab ) {
311 nbptab = ntab->nt_next;
315 * Check for another nbptab entry with the same zone. If
316 * there isn't one, find the ziptab entry for the zone and
317 * remove the multicast address from the appropriate interfaces.
321 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
326 * Couple of things: 1. Unless we have the -t flag (which is sort
327 * of a misnomer, since you need it if you're doing any phase 1
328 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
329 * and we know what the sender meant by '*', we copy the real
330 * zone into the packet.
332 if ( nn.nn_zonelen == 0 ||
333 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
334 iface = ap->ap_iface;
335 if ( iface && iface->i_rt->rt_zt ) {
336 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
337 } else if ( interfaces->i_next->i_rt->rt_zt ) {
338 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
344 * Copy zone into packet. Note that we're changing len, data, and
345 * nbpop. Later, we'll use ( data - len ) to mean the beginning
349 memcpy( packet, data - len, len );
350 nbpop = packet + ( len - ( data - nbpop ));
351 data = packet + ( len - ( data - zonep ));
352 *data++ = zt->zt_len;
353 memcpy( data, zt->zt_name, zt->zt_len );
358 for ( zt = ziptab; zt; zt = zt->zt_next ) {
359 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
360 nn.nn_zone, zt->zt_len ) == 0 ) {
365 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
371 * If we've got no zones, send out LKUP on the local net.
372 * Otherwise, look through the zone table.
376 sat.sat_len = sizeof( struct sockaddr_at );
378 sat.sat_family = AF_APPLETALK;
379 sat.sat_port = ap->ap_port;
381 nh.nh_op = NBPOP_LKUP;
382 memcpy( nbpop, &nh, SZ_NBPHDR );
383 sat.sat_addr.s_net = 0; /* XXX */
384 sat.sat_addr.s_node = ATADDR_BCAST;
386 /* Find the first non-loopback ap */
387 for ( iface = interfaces; iface; iface = iface->i_next ) {
388 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
389 (iface == ap->ap_iface ||
390 (iface->i_flags & IFACE_ISROUTER))) {
397 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
398 if ( ap->ap_packet == nbp_packet ) {
403 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
404 sizeof( struct sockaddr_at )) < 0 ) {
405 syslog( LOG_ERR, "nbp brrq sendto: %m" );
411 sat.sat_len = sizeof( struct sockaddr_at );
413 sat.sat_family = AF_APPLETALK;
414 sat.sat_port = ap->ap_port;
415 for ( l = zt->zt_rt; l; l = l->l_next ) {
416 rtmp = (struct rtmptab *)l->l_data;
418 if ( rtmp->rt_gate == 0 ) {
419 for ( iface = interfaces; iface;
420 iface = iface->i_next ) {
421 if ( iface->i_rt == rtmp ) {
426 syslog( LOG_ERR, "nbp_packet: \
427 Can't find route's interface!" );
432 ap = rtmp->rt_gate->g_iface->i_ports;
434 for ( ; ap; ap = ap->ap_next ) {
435 if ( ap->ap_packet == nbp_packet ) {
440 syslog( LOG_ERR, "nbp_packet: Can't find port!" );
445 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
446 if ( rtmp->rt_gate == 0 ) {
449 nh.nh_op = NBPOP_LKUP;
450 memcpy( nbpop, &nh, SZ_NBPHDR );
451 sat.sat_addr.s_net = rtmp->rt_firstnet;
452 sat.sat_addr.s_node = ATADDR_BCAST;
454 if ( rtmp->rt_gate == 0 ) {
455 nh.nh_op = NBPOP_LKUP;
456 memcpy( nbpop, &nh, SZ_NBPHDR );
457 sat.sat_addr.s_net = 0;
458 sat.sat_addr.s_node = ATADDR_BCAST;
461 nh.nh_op = NBPOP_FWD;
462 memcpy( nbpop, &nh, SZ_NBPHDR );
463 sat.sat_addr.s_net = rtmp->rt_firstnet;
464 sat.sat_addr.s_node = 0;
468 if ( sendto( ap->ap_fd, data - len, len, 0,
469 (struct sockaddr *)&sat,
470 sizeof( struct sockaddr_at )) < 0 ) {
471 syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
472 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
484 /* send lkup on net. we need to make sure we're a router. */
485 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
486 nh.nh_op = NBPOP_LKUP;
487 memcpy( nbpop, &nh, SZ_NBPHDR );
488 from->sat_addr.s_net = 0;
489 from->sat_addr.s_node = ATADDR_BCAST;
490 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
491 sizeof( struct sockaddr_at )) < 0 ) {
492 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
493 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
500 /* search our data */
502 data = packet + 1 + SZ_NBPHDR;
503 end = packet + sizeof( packet );
505 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
506 /* don't send out entries if we don't want to route. */
507 if ((ap->ap_iface != ntab->nt_iface) &&
508 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
512 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
513 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
514 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
520 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
521 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
522 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
528 if ( nn.nn_zonelen != 0 &&
529 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
530 if ( ntab->nt_nve.nn_zonelen == 0 ||
531 ( ntab->nt_nve.nn_zonelen == 1 &&
532 *ntab->nt_nve.nn_zone == '*' )) {
533 if ( interfaces->i_next->i_rt->rt_zt ) {
534 zt = (struct ziptab *)interfaces->i_next->i_rt->
536 if ( zt->zt_len != nn.nn_zonelen ||
537 strndiacasecmp( zt->zt_name, nn.nn_zone,
543 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
544 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
552 * Another tuple won't fit. Send what we've already
553 * got, and start the next packet.
555 if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
556 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
557 nh.nh_op = NBPOP_LKUPREPLY;
561 *data++ = DDPTYPE_NBP;
562 memcpy( data, &nh, SZ_NBPHDR );
564 if ( sendto( ap->ap_fd, packet, cc, 0,
565 (struct sockaddr *)&nn.nn_sat,
566 sizeof( struct sockaddr_at )) < 0 ) {
567 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
568 ntohs( nn.nn_sat.sat_addr.s_net ),
569 nn.nn_sat.sat_addr.s_node );
574 data = packet + 1 + SZ_NBPHDR;
575 end = packet + sizeof( packet );
578 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
579 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
580 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
582 * Right now, we'll just give each name a unique enum. In
583 * the future, we might need to actually assign and save
584 * an enum, based on the associated address. For the moment,
585 * the enums will be unique and constant, since the order
590 memcpy( data, &nt, SZ_NBPTUPLE );
593 *data++ = ntab->nt_nve.nn_objlen;
594 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
595 data += ntab->nt_nve.nn_objlen;
597 *data++ = ntab->nt_nve.nn_typelen;
598 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
599 data += ntab->nt_nve.nn_typelen;
602 * Macs won't see something with a zone of 0 length. We
603 * will always return '*' instead. Perhaps we should
604 * unconditionally return the real zone?
606 if ( ntab->nt_nve.nn_zonelen ) {
607 *data++ = ntab->nt_nve.nn_zonelen;
608 memcpy( data, ntab->nt_nve.nn_zone, ntab->nt_nve.nn_zonelen );
609 data += ntab->nt_nve.nn_zonelen;
619 nh.nh_op = NBPOP_LKUPREPLY;
623 *data++ = DDPTYPE_NBP;
624 memcpy( data, &nh, SZ_NBPHDR );
626 if ( sendto( ap->ap_fd, packet, cc, 0,
627 (struct sockaddr *)&nn.nn_sat,
628 sizeof( struct sockaddr_at )) < 0 ) {
629 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
630 ntohs( nn.nn_sat.sat_addr.s_net ),
631 nn.nn_sat.sat_addr.s_node );
638 syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );