2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
12 #include <sys/syslog.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/socket.h>
16 #include <sys/ioctl.h>
18 #include <netatalk/at.h>
19 #include <atalk/ddp.h>
20 #include <atalk/atp.h>
21 #include <atalk/nbp.h>
22 #include <atalk/util.h>
25 #include <sys/sockio.h>
29 #include "interface.h"
35 #include "multicast.h"
37 extern int transition;
39 struct nbptab *nbptab = NULL;
42 void nbp_ack( fd, nh_op, nh_id, to )
46 struct sockaddr_at *to;
49 char *data, packet[ SZ_NBPHDR + 1 ];
55 *data++ = DDPTYPE_NBP;
56 bcopy( &nh, data, SZ_NBPHDR );
58 if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
59 sizeof( struct sockaddr_at )) < 0 ) {
60 syslog( LOG_ERR, "sendto: %m" );
64 int nbp_packet( ap, from, data, len )
66 struct sockaddr_at *from;
73 struct sockaddr_at sat;
76 struct interface *iface;
79 char *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
80 int n, i, cc, locallkup;
84 syslog( LOG_INFO, "nbp_packet malformed packet" );
87 if ( *data++ != DDPTYPE_NBP ) {
88 syslog( LOG_INFO, "nbp_packet bad ddp type" );
92 if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
93 syslog( LOG_INFO, "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 syslog( LOG_INFO, "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 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
119 syslog( LOG_INFO, "nbp_packet: malformed packet" );
122 nn.nn_objlen = *data++;
123 memcpy( nn.nn_obj, data, nn.nn_objlen );
124 data += nn.nn_objlen;
127 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
128 syslog( LOG_INFO, "nbp_packet: malformed packet" );
131 nn.nn_typelen = *data++;
132 memcpy( nn.nn_type, data, nn.nn_typelen );
133 data += nn.nn_typelen;
136 if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
137 syslog( LOG_INFO, "nbp_packet: malformed packet" );
140 zonep = data; /* remember for fwd */
141 nn.nn_zonelen = *data++;
142 memcpy( nn.nn_zone, data, nn.nn_zonelen );
143 data += nn.nn_zonelen;
146 syslog( LOG_INFO, "nbp_packet: malformed packet" );
151 switch ( nh.nh_op ) {
155 * Find the ziptab entry for the zone we're trying to register in.
157 if ( nn.nn_zonelen == 0 ||
158 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
159 if ( interfaces->i_next->i_rt->rt_zt ) {
160 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
165 for ( zt = ziptab; zt; zt = zt->zt_next ) {
166 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
167 nn.nn_zone, zt->zt_len ) == 0 ) {
172 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
178 * Observe that we don't have to do any local-zone verification
179 * if the zone aleady has a multicast address set.
181 if ( zt != 0 && zt->zt_bcast == 0 ) {
183 * Check if zone is associated with any of our local interfaces.
185 for ( iface = interfaces; iface; iface = iface->i_next ) {
186 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
187 if ( zt == (struct ziptab *)l->l_data ) {
196 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
200 /* calculate and save multicast address */
201 if (zone_bcast(zt) < 0) {
202 syslog(LOG_ERR, "nbp_packet: zone_bcast");
206 for ( iface = interfaces; iface; iface = iface->i_next ) {
207 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
210 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
211 if ( zt == (struct ziptab *)l->l_data ) {
213 if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
214 syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
222 if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
224 syslog( LOG_ERR, "nbp_packet: malloc: %m" );
227 memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
228 ntab->nt_iface = ap->ap_iface;
229 ntab->nt_next = nbptab;
232 nbptab->nt_prev = ntab;
236 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
240 /* deal with local zone info */
241 if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
242 ( nn.nn_zonelen == 0 )) {
244 if ( interfaces->i_next->i_rt->rt_zt ) {
245 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
251 /* remove from our data, perhaps removing a multicast address */
252 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
253 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
254 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
258 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
259 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
264 * I *think* we really do check the zone, here.
266 * i changed it to better handle local zone cases as well.
270 /* match local zones */
272 /* ntab is also local zone */
273 if (( ntab->nt_nve.nn_zonelen == 1 &&
274 *ntab->nt_nve.nn_zone == '*' ) ||
275 (ntab->nt_nve.nn_zonelen == 0))
278 /* ntab is default zone */
279 if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
280 (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
286 /* match particular zone */
287 if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
288 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
289 nn.nn_zonelen ) == 0)) {
294 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
298 if ( ntab->nt_next != 0 ) {
299 ntab->nt_next->nt_prev = ntab->nt_prev;
301 if ( ntab->nt_prev != 0 ) {
302 ntab->nt_prev->nt_next = ntab->nt_next;
304 if ( ntab == nbptab ) {
305 nbptab = ntab->nt_next;
309 * Check for another nbptab entry with the same zone. If
310 * there isn't one, find the ziptab entry for the zone and
311 * remove the multicast address from the appropriate interfaces.
315 nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
320 * Couple of things: 1. Unless we have the -t flag (which is sort
321 * of a misnomer, since you need it if you're doing any phase 1
322 * work), always send NBPOP_FWD. 2. If we get a zone of '*',
323 * and we know what the sender meant by '*', we copy the real
324 * zone into the packet.
326 if ( nn.nn_zonelen == 0 ||
327 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
328 iface = ap->ap_iface;
329 if ( iface && iface->i_rt->rt_zt ) {
330 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
331 } else if ( interfaces->i_next->i_rt->rt_zt ) {
332 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
338 * Copy zone into packet. Note that we're changing len, data, and
339 * nbpop. Later, we'll use ( data - len ) to mean the beginning
343 memcpy( packet, data - len, len );
344 nbpop = packet + ( len - ( data - nbpop ));
345 data = packet + ( len - ( data - zonep ));
346 *data++ = zt->zt_len;
347 memcpy( data, zt->zt_name, zt->zt_len );
352 for ( zt = ziptab; zt; zt = zt->zt_next ) {
353 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
354 nn.nn_zone, zt->zt_len ) == 0 ) {
359 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
365 * If we've got no zones, send out LKUP on the local net.
366 * Otherwise, look through the zone table.
370 sat.sat_len = sizeof( struct sockaddr_at );
372 sat.sat_family = AF_APPLETALK;
373 sat.sat_port = ap->ap_port;
375 nh.nh_op = NBPOP_LKUP;
376 memcpy( nbpop, &nh, SZ_NBPHDR );
377 sat.sat_addr.s_net = 0; /* XXX */
378 sat.sat_addr.s_node = ATADDR_BCAST;
380 /* Find the first non-loopback ap */
381 for ( iface = interfaces; iface; iface = iface->i_next ) {
382 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
383 (iface == ap->ap_iface ||
384 (iface->i_flags & IFACE_ISROUTER))) {
391 for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
392 if ( ap->ap_packet == nbp_packet ) {
397 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
398 sizeof( struct sockaddr_at )) < 0 ) {
399 syslog( LOG_ERR, "nbp brrq sendto: %m" );
405 sat.sat_len = sizeof( struct sockaddr_at );
407 sat.sat_family = AF_APPLETALK;
408 sat.sat_port = ap->ap_port;
409 for ( l = zt->zt_rt; l; l = l->l_next ) {
410 rtmp = (struct rtmptab *)l->l_data;
412 if ( rtmp->rt_gate == 0 ) {
413 for ( iface = interfaces; iface;
414 iface = iface->i_next ) {
415 if ( iface->i_rt == rtmp ) {
420 syslog( LOG_ERR, "nbp_packet: \
421 Can't find route's interface!" );
426 ap = rtmp->rt_gate->g_iface->i_ports;
428 for ( ; ap; ap = ap->ap_next ) {
429 if ( ap->ap_packet == nbp_packet ) {
434 syslog( LOG_ERR, "nbp_packet: Can't find port!" );
439 ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
440 if ( rtmp->rt_gate == 0 ) {
443 nh.nh_op = NBPOP_LKUP;
444 bcopy( &nh, nbpop, SZ_NBPHDR );
445 sat.sat_addr.s_net = rtmp->rt_firstnet;
446 sat.sat_addr.s_node = ATADDR_BCAST;
448 if ( rtmp->rt_gate == 0 ) {
449 nh.nh_op = NBPOP_LKUP;
450 bcopy( &nh, nbpop, SZ_NBPHDR );
451 sat.sat_addr.s_net = 0;
452 sat.sat_addr.s_node = ATADDR_BCAST;
455 nh.nh_op = NBPOP_FWD;
456 bcopy( &nh, nbpop, SZ_NBPHDR );
457 sat.sat_addr.s_net = rtmp->rt_firstnet;
458 sat.sat_addr.s_node = 0;
462 if ( sendto( ap->ap_fd, data - len, len, 0,
463 (struct sockaddr *)&sat,
464 sizeof( struct sockaddr_at )) < 0 ) {
465 syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
466 ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
478 /* send lkup on net. we need to make sure we're a router. */
479 if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
480 nh.nh_op = NBPOP_LKUP;
481 bcopy( &nh, nbpop, SZ_NBPHDR );
482 from->sat_addr.s_net = 0;
483 from->sat_addr.s_node = ATADDR_BCAST;
484 if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
485 sizeof( struct sockaddr_at )) < 0 ) {
486 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
487 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
494 /* search our data */
496 data = packet + 1 + SZ_NBPHDR;
497 end = packet + sizeof( packet );
499 for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
500 /* don't send out entries if we don't want to route. */
501 if ((ap->ap_iface != ntab->nt_iface) &&
502 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
506 if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
507 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
508 strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
514 if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
515 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
516 strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
522 if ( nn.nn_zonelen != 0 &&
523 ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
524 if ( ntab->nt_nve.nn_zonelen == 0 ||
525 ( ntab->nt_nve.nn_zonelen == 1 &&
526 *ntab->nt_nve.nn_zone == '*' )) {
527 if ( interfaces->i_next->i_rt->rt_zt ) {
528 zt = (struct ziptab *)interfaces->i_next->i_rt->
530 if ( zt->zt_len != nn.nn_zonelen ||
531 strndiacasecmp( zt->zt_name, nn.nn_zone,
537 if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
538 strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
546 * Another tuple won't fit. Send what we've already
547 * got, and start the next packet.
549 if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
550 ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
551 nh.nh_op = NBPOP_LKUPREPLY;
555 *data++ = DDPTYPE_NBP;
556 bcopy( &nh, data, SZ_NBPHDR );
558 if ( sendto( ap->ap_fd, packet, cc, 0,
559 (struct sockaddr *)&nn.nn_sat,
560 sizeof( struct sockaddr_at )) < 0 ) {
561 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
562 ntohs( nn.nn_sat.sat_addr.s_net ),
563 nn.nn_sat.sat_addr.s_node );
568 data = packet + 1 + SZ_NBPHDR;
569 end = packet + sizeof( packet );
572 nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
573 nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
574 nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
576 * Right now, we'll just give each name a unique enum. In
577 * the future, we might need to actually assign and save
578 * an enum, based on the associated address. For the moment,
579 * the enums will be unique and constant, since the order
584 memcpy( data, &nt, SZ_NBPTUPLE );
587 *data++ = ntab->nt_nve.nn_objlen;
588 memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
589 data += ntab->nt_nve.nn_objlen;
591 *data++ = ntab->nt_nve.nn_typelen;
592 memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
593 data += ntab->nt_nve.nn_typelen;
596 * Macs won't see something with a zone of 0 length. We
597 * will always return '*' instead. Perhaps we should
598 * unconditionally return the real zone?
600 if ( ntab->nt_nve.nn_zonelen ) {
601 *data++ = ntab->nt_nve.nn_zonelen;
602 bcopy( ntab->nt_nve.nn_zone, data, ntab->nt_nve.nn_zonelen );
603 data += ntab->nt_nve.nn_zonelen;
613 nh.nh_op = NBPOP_LKUPREPLY;
617 *data++ = DDPTYPE_NBP;
618 bcopy( &nh, data, SZ_NBPHDR );
620 if ( sendto( ap->ap_fd, packet, cc, 0,
621 (struct sockaddr *)&nn.nn_sat,
622 sizeof( struct sockaddr_at )) < 0 ) {
623 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
624 ntohs( nn.nn_sat.sat_addr.s_net ),
625 nn.nn_sat.sat_addr.s_node );
632 syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );