2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
8 #include <sys/syslog.h>
10 #include <sys/param.h>
11 #include <sys/socket.h>
12 #include <sys/ioctl.h>
14 #include <netatalk/at.h>
15 #include <atalk/ddp.h>
16 #include <atalk/atp.h>
17 #include <atalk/nbp.h>
18 #include <atalk/util.h>
21 #include <sys/sockio.h>
25 #include "interface.h"
31 #include "multicast.h"
33 extern int transition;
35 struct nbptab *nbptab = NULL;
38 void nbp_ack( fd, nh_op, nh_id, to )
42 struct sockaddr_at *to;
45 char *data, packet[ SZ_NBPHDR + 1 ];
51 *data++ = DDPTYPE_NBP;
52 bcopy( &nh, data, SZ_NBPHDR );
54 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
55 sizeof( struct sockaddr_at )) < 0 ) {
56 syslog( LOG_ERR, "sendto: %m" );
60 int nbp_packet( ap, from, data, len )
62 struct sockaddr_at *from;
69 struct sockaddr_at sat;
72 struct interface *iface;
75 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
76 int n, i, cc, locallkup;
80 syslog( LOG_INFO, "nbp_packet malformed packet" );
83 if ( *data++ != DDPTYPE_NBP ) {
84 syslog( LOG_INFO, "nbp_packet bad ddp type" );
88 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
89 syslog( LOG_INFO, "nbp_packet: malformed packet" );
92 memcpy( &nh, data, SZ_NBPHDR );
93 nbpop = data; /* remember for fwd and brrq */
95 if ( nh.nh_cnt != 1 ) {
96 syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
101 memcpy( &nt, data, SZ_NBPTUPLE );
104 memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
106 nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
108 nn.nn_sat.sat_family = AF_APPLETALK;
109 nn.nn_sat.sat_addr.s_net = nt.nt_net;
110 nn.nn_sat.sat_addr.s_node = nt.nt_node;
111 nn.nn_sat.sat_port = nt.nt_port;
114 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
115 syslog( LOG_INFO, "nbp_packet: malformed packet" );
118 nn.nn_objlen = *data++;
119 memcpy( nn.nn_obj, data, nn.nn_objlen );
120 data += nn.nn_objlen;
123 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
124 syslog( LOG_INFO, "nbp_packet: malformed packet" );
127 nn.nn_typelen = *data++;
128 memcpy( nn.nn_type, data, nn.nn_typelen );
129 data += nn.nn_typelen;
132 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
133 syslog( LOG_INFO, "nbp_packet: malformed packet" );
136 zonep = data; /* remember for fwd */
137 nn.nn_zonelen = *data++;
138 memcpy( nn.nn_zone, data, nn.nn_zonelen );
139 data += nn.nn_zonelen;
142 syslog( LOG_INFO, "nbp_packet: malformed packet" );
147 switch ( nh.nh_op ) {
151 * Find the ziptab entry for the zone we're trying to register in.
153 if ( nn.nn_zonelen == 0 ||
154 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
155 if ( interfaces->i_next->i_rt->rt_zt ) {
156 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
161 for ( zt = ziptab; zt; zt = zt->zt_next ) {
162 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
163 nn.nn_zone, zt->zt_len ) == 0 ) {
168 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
174 * Observe that we don't have to do any local-zone verification
175 * if the zone aleady has a multicast address set.
177 if ( zt != 0 && zt->zt_bcast == 0 ) {
179 * Check if zone is associated with any of our local interfaces.
181 for ( iface = interfaces; iface; iface = iface->i_next ) {
182 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
183 if ( zt == (struct ziptab *)l->l_data ) {
192 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
196 /* calculate and save multicast address */
197 if (zone_bcast(zt) < 0) {
198 syslog(LOG_ERR, "nbp_packet: zone_bcast");
202 for ( iface = interfaces; iface; iface = iface->i_next ) {
203 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
206 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
207 if ( zt == (struct ziptab *)l->l_data ) {
209 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
210 syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
218 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
220 syslog( LOG_ERR, "nbp_packet: malloc: %m" );
223 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
224 ntab->nt_iface = ap->ap_iface;
225 ntab->nt_next = nbptab;
228 nbptab->nt_prev = ntab;
232 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
236 /* deal with local zone info */
237 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
238 ( nn.nn_zonelen == 0 )) {
240 if ( interfaces->i_next->i_rt->rt_zt ) {
241 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
247 /* remove from our data, perhaps removing a multicast address */
248 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
249 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
250 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
254 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
255 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
260 * I *think* we really do check the zone, here.
262 * i changed it to better handle local zone cases as well.
266 /* match local zones */
268 /* ntab is also local zone */
269 if (( ntab->nt_nve.nn_zonelen == 1 &&
270 *ntab->nt_nve.nn_zone == '*' ) ||
271 (ntab->nt_nve.nn_zonelen == 0))
274 /* ntab is default zone */
275 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
276 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
282 /* match particular zone */
283 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
284 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
285 nn.nn_zonelen ) == 0)) {
290 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
294 if ( ntab->nt_next != 0 ) {
295 ntab->nt_next->nt_prev = ntab->nt_prev;
297 if ( ntab->nt_prev != 0 ) {
298 ntab->nt_prev->nt_next = ntab->nt_next;
300 if ( ntab == nbptab ) {
301 nbptab = ntab->nt_next;
305 * Check for another nbptab entry with the same zone. If
306 * there isn't one, find the ziptab entry for the zone and
307 * remove the multicast address from the appropriate interfaces.
311 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
316 * Couple of things: 1. Unless we have the -t flag (which is sort
317 * of a misnomer, since you need it if you're doing any phase 1
318 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
319 * and we know what the sender meant by '*', we copy the real
320 * zone into the packet.
322 if ( nn.nn_zonelen == 0 ||
323 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
324 iface = ap->ap_iface;
325 if ( iface && iface->i_rt->rt_zt ) {
326 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
327 } else if ( interfaces->i_next->i_rt->rt_zt ) {
328 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
334 * Copy zone into packet. Note that we're changing len, data, and
335 * nbpop. Later, we'll use ( data - len ) to mean the beginning
339 memcpy( packet, data - len, len );
340 nbpop = packet + ( len - ( data - nbpop ));
341 data = packet + ( len - ( data - zonep ));
342 *data++ = zt->zt_len;
343 memcpy( data, zt->zt_name, zt->zt_len );
348 for ( zt = ziptab; zt; zt = zt->zt_next ) {
349 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
350 nn.nn_zone, zt->zt_len ) == 0 ) {
355 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
361 * If we've got no zones, send out LKUP on the local net.
362 * Otherwise, look through the zone table.
366 sat.sat_len = sizeof( struct sockaddr_at );
368 sat.sat_family = AF_APPLETALK;
369 sat.sat_port = ap->ap_port;
371 nh.nh_op = NBPOP_LKUP;
372 memcpy( nbpop, &nh, SZ_NBPHDR );
373 sat.sat_addr.s_net = 0; /* XXX */
374 sat.sat_addr.s_node = ATADDR_BCAST;
376 /* Find the first non-loopback ap */
377 for ( iface = interfaces; iface; iface = iface->i_next ) {
378 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
379 (iface == ap->ap_iface ||
380 (iface->i_flags & IFACE_ISROUTER))) {
387 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
388 if ( ap->ap_packet == nbp_packet ) {
393 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
394 sizeof( struct sockaddr_at )) < 0 ) {
395 syslog( LOG_ERR, "nbp brrq sendto: %m" );
401 sat.sat_len = sizeof( struct sockaddr_at );
403 sat.sat_family = AF_APPLETALK;
404 sat.sat_port = ap->ap_port;
405 for ( l = zt->zt_rt; l; l = l->l_next ) {
406 rtmp = (struct rtmptab *)l->l_data;
408 if ( rtmp->rt_gate == 0 ) {
409 for ( iface = interfaces; iface;
410 iface = iface->i_next ) {
411 if ( iface->i_rt == rtmp ) {
416 syslog( LOG_ERR, "nbp_packet: \
417 Can't find route's interface!" );
422 ap = rtmp->rt_gate->g_iface->i_ports;
424 for ( ; ap; ap = ap->ap_next ) {
425 if ( ap->ap_packet == nbp_packet ) {
430 syslog( LOG_ERR, "nbp_packet: Can't find port!" );
435 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
436 if ( rtmp->rt_gate == 0 ) {
439 nh.nh_op = NBPOP_LKUP;
440 bcopy( &nh, nbpop, SZ_NBPHDR );
441 sat.sat_addr.s_net = rtmp->rt_firstnet;
442 sat.sat_addr.s_node = ATADDR_BCAST;
444 if ( rtmp->rt_gate == 0 ) {
445 nh.nh_op = NBPOP_LKUP;
446 bcopy( &nh, nbpop, SZ_NBPHDR );
447 sat.sat_addr.s_net = 0;
448 sat.sat_addr.s_node = ATADDR_BCAST;
451 nh.nh_op = NBPOP_FWD;
452 bcopy( &nh, nbpop, SZ_NBPHDR );
453 sat.sat_addr.s_net = rtmp->rt_firstnet;
454 sat.sat_addr.s_node = 0;
458 if ( sendto( ap->ap_fd, data - len, len, 0,
459 (struct sockaddr *)&sat,
460 sizeof( struct sockaddr_at )) < 0 ) {
461 syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
462 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
474 /* send lkup on net. we need to make sure we're a router. */
475 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
476 nh.nh_op = NBPOP_LKUP;
477 bcopy( &nh, nbpop, SZ_NBPHDR );
478 from->sat_addr.s_net = 0;
479 from->sat_addr.s_node = ATADDR_BCAST;
480 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
481 sizeof( struct sockaddr_at )) < 0 ) {
482 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
483 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
490 /* search our data */
492 data = packet + 1 + SZ_NBPHDR;
493 end = packet + sizeof( packet );
495 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
496 /* don't send out entries if we don't want to route. */
497 if ((ap->ap_iface != ntab->nt_iface) &&
498 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
502 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
503 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
504 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
510 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
511 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
512 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
518 if ( nn.nn_zonelen != 0 &&
519 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
520 if ( ntab->nt_nve.nn_zonelen == 0 ||
521 ( ntab->nt_nve.nn_zonelen == 1 &&
522 *ntab->nt_nve.nn_zone == '*' )) {
523 if ( interfaces->i_next->i_rt->rt_zt ) {
524 zt = (struct ziptab *)interfaces->i_next->i_rt->
526 if ( zt->zt_len != nn.nn_zonelen ||
527 strndiacasecmp( zt->zt_name, nn.nn_zone,
533 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
534 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
542 * Another tuple won't fit. Send what we've already
543 * got, and start the next packet.
545 if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
546 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
547 nh.nh_op = NBPOP_LKUPREPLY;
551 *data++ = DDPTYPE_NBP;
552 bcopy( &nh, data, SZ_NBPHDR );
554 if ( sendto( ap->ap_fd, packet, cc, 0,
555 (struct sockaddr *)&nn.nn_sat,
556 sizeof( struct sockaddr_at )) < 0 ) {
557 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
558 ntohs( nn.nn_sat.sat_addr.s_net ),
559 nn.nn_sat.sat_addr.s_node );
564 data = packet + 1 + SZ_NBPHDR;
565 end = packet + sizeof( packet );
568 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
569 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
570 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
572 * Right now, we'll just give each name a unique enum. In
573 * the future, we might need to actually assign and save
574 * an enum, based on the associated address. For the moment,
575 * the enums will be unique and constant, since the order
580 memcpy( data, &nt, SZ_NBPTUPLE );
583 *data++ = ntab->nt_nve.nn_objlen;
584 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
585 data += ntab->nt_nve.nn_objlen;
587 *data++ = ntab->nt_nve.nn_typelen;
588 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
589 data += ntab->nt_nve.nn_typelen;
592 * Macs won't see something with a zone of 0 length. We
593 * will always return '*' instead. Perhaps we should
594 * unconditionally return the real zone?
596 if ( ntab->nt_nve.nn_zonelen ) {
597 *data++ = ntab->nt_nve.nn_zonelen;
598 bcopy( ntab->nt_nve.nn_zone, data, ntab->nt_nve.nn_zonelen );
599 data += ntab->nt_nve.nn_zonelen;
609 nh.nh_op = NBPOP_LKUPREPLY;
613 *data++ = DDPTYPE_NBP;
614 bcopy( &nh, data, SZ_NBPHDR );
616 if ( sendto( ap->ap_fd, packet, cc, 0,
617 (struct sockaddr *)&nn.nn_sat,
618 sizeof( struct sockaddr_at )) < 0 ) {
619 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
620 ntohs( nn.nn_sat.sat_addr.s_net ),
621 nn.nn_sat.sat_addr.s_node );
628 syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );