]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/nbp.c
replaced all #include <sys/syslog.h> with #include <syslog.h>
[netatalk.git] / etc / atalkd / nbp.c
1 /*
2  * $Id: nbp.c,v 1.7 2002-01-03 17:49:39 sibaz Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <syslog.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #ifdef TRU64
21 #include <sys/mbuf.h>
22 #include <net/route.h>
23 #endif /* TRU64 */
24 #include <net/if.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>
30
31 #ifdef __svr4__
32 #include <sys/sockio.h>
33 #endif /* __svr4__ */
34
35 #include "atserv.h"
36 #include "interface.h"
37 #include "list.h"
38 #include "rtmp.h"
39 #include "gate.h"
40 #include "zip.h"
41 #include "nbp.h"
42 #include "multicast.h"
43
44 extern int      transition;
45
46 struct nbptab   *nbptab = NULL;
47
48 static 
49 void nbp_ack( fd, nh_op, nh_id, to )
50     int                 fd;
51     int                 nh_op;
52     int                 nh_id;
53     struct sockaddr_at  *to;
54 {
55     struct nbphdr       nh;
56     char                *data, packet[ SZ_NBPHDR + 1 ];
57
58     nh.nh_op = nh_op;
59     nh.nh_cnt = 0;
60     nh.nh_id = nh_id;
61     data = packet;
62     *data++ = DDPTYPE_NBP;
63     memcpy( data, &nh, SZ_NBPHDR );
64     data += 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) );
68     }
69 }
70
71 int nbp_packet( ap, from, data, len )
72     struct atport       *ap;
73     struct sockaddr_at  *from;
74     char                *data;
75     int                 len;
76 {
77     struct nbphdr       nh;
78     struct nbptuple     nt;
79     struct nbpnve       nn;
80     struct sockaddr_at  sat;
81     struct nbptab       *ntab;
82     struct ziptab       *zt;
83     struct interface    *iface;
84     struct list         *l;
85     struct rtmptab      *rtmp;
86     char                *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
87     int                 n, i, cc, locallkup;
88
89     end = data + len;
90     if ( data >= end ) {
91         syslog( LOG_INFO, "nbp_packet malformed packet" );
92         return 1;
93     }
94     if ( *data++ != DDPTYPE_NBP ) {
95         syslog( LOG_INFO, "nbp_packet bad ddp type" );
96         return 1;
97     }
98
99     if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
100         syslog( LOG_INFO, "nbp_packet: malformed packet" );
101         return 1;
102     }
103     memcpy( &nh, data, SZ_NBPHDR );
104     nbpop = data;                       /* remember for fwd and brrq */
105     data += SZ_NBPHDR;
106     if ( nh.nh_cnt != 1 ) {
107         syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
108                 nh.nh_op );
109         return 1;
110     }
111
112     memcpy( &nt, data, SZ_NBPTUPLE );
113     data += SZ_NBPTUPLE;
114
115     memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
116 #ifdef BSD4_4
117     nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
118 #endif /* BSD4_4 */
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;
123
124     /* object */
125     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
126         syslog( LOG_INFO, "nbp_packet: malformed packet" );
127         return 1;
128     }
129     nn.nn_objlen = *data++;
130     memcpy( nn.nn_obj, data, nn.nn_objlen );
131     data += nn.nn_objlen;
132
133     /* type */
134     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
135         syslog( LOG_INFO, "nbp_packet: malformed packet" );
136         return 1;
137     }
138     nn.nn_typelen = *data++;
139     memcpy( nn.nn_type, data, nn.nn_typelen );
140     data += nn.nn_typelen;
141
142     /* zone */
143     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
144         syslog( LOG_INFO, "nbp_packet: malformed packet" );
145         return 1;
146     }
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;
151
152     if ( data != end ) {
153         syslog( LOG_INFO, "nbp_packet: malformed packet" );
154         return 1;
155     }
156
157     locallkup = 0;
158     switch ( nh.nh_op ) {
159
160     case NBPOP_RGSTR :
161         /*
162          * Find the ziptab entry for the zone we're trying to register in.
163          */
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;
168             } else {
169                 zt = 0;
170             }
171         } else {
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 ) {
175                     break;
176                 }
177             }
178             if ( zt == 0 ) {
179                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
180                 return 0;
181             }
182         }
183
184         /*
185          * Observe that we don't have to do any local-zone verification
186          * if the zone aleady has a multicast address set.
187          */
188         if ( zt != 0 && zt->zt_bcast == 0 ) {
189             /*
190              * Check if zone is associated with any of our local interfaces.
191              */
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 ) {
195                         break;
196                     }
197                 }
198                 if ( l != 0 ) {
199                     break;
200                 }
201             }
202             if ( iface == 0 ) {
203                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
204                 return 0;
205             }
206
207             /* calculate and save multicast address */
208             if (zone_bcast(zt) < 0) {
209                 syslog(LOG_ERR, "nbp_packet: zone_bcast");
210                 return -1;
211             }
212
213             for ( iface = interfaces; iface; iface = iface->i_next ) {
214                 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
215                     continue;
216                 }
217                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
218                     if ( zt == (struct ziptab *)l->l_data ) {
219                         /* add multicast */
220                         if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
221                             syslog( LOG_ERR, "nbp_packet: addmulti: %s",
222                                     strerror(errno) );
223                             return -1;
224                         }
225                     }
226                 }
227             }
228         }
229
230         if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
231                 == 0 ) {
232             syslog( LOG_ERR, "nbp_packet: malloc: %s", strerror(errno) );
233             return -1;
234         }
235         memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
236         ntab->nt_iface = ap->ap_iface;
237         ntab->nt_next = nbptab;
238         ntab->nt_prev = 0;
239         if ( nbptab ) {
240             nbptab->nt_prev = ntab;
241         }
242         nbptab = ntab;
243
244         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
245         break;
246
247     case NBPOP_UNRGSTR :
248         /* deal with local zone info */
249         if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
250             ( nn.nn_zonelen == 0 )) {
251           locallkup = 1;
252           if ( interfaces->i_next->i_rt->rt_zt ) {
253             zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
254           } else {
255             zt = NULL;
256           }
257         }
258
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,
263                     nn.nn_objlen )) {
264                 continue;
265             }
266             if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
267                     strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
268                     nn.nn_typelen )) {
269                 continue;
270             }
271             /*
272              * I *think* we really do check the zone, here.
273              *
274              * i changed it to better handle local zone cases as well.
275              * -- asun
276              */
277             
278             /* match local zones */
279             if (locallkup) {
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))
284                 break;
285               
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,
289                                   zt->zt_len) == 0)) {
290                 break;
291               }
292             }
293             
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)) {
298                 break;
299             }
300         }
301         if ( ntab == 0 ) {
302             nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
303             return 0;
304         }
305
306         if ( ntab->nt_next != 0 ) {
307             ntab->nt_next->nt_prev = ntab->nt_prev;
308         }
309         if ( ntab->nt_prev != 0 ) {
310             ntab->nt_prev->nt_next = ntab->nt_next;
311         }
312         if ( ntab == nbptab ) {
313             nbptab = ntab->nt_next;
314         }
315
316         /*
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.
320          * XXX
321          */
322
323         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
324         break;
325
326     case NBPOP_BRRQ :
327         /*
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.
333          */
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;
341             } else {
342                 zt = NULL;
343             }
344
345             /*
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
348              * of this packet.
349              */
350             if ( zt ) {
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 );
356                 data += zt->zt_len;
357                 len = data - packet;
358             }
359         } else {
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 ) {
363                     break;
364                 }
365             }
366             if ( zt == 0 ) {
367                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
368                 return 0;
369             }
370         }
371
372         /*
373          * If we've got no zones, send out LKUP on the local net.
374          * Otherwise, look through the zone table.
375          */
376         if ( zt == 0 ) {
377 #ifdef BSD4_4
378             sat.sat_len = sizeof( struct sockaddr_at );
379 #endif /* BSD4_4 */
380             sat.sat_family = AF_APPLETALK;
381             sat.sat_port = ap->ap_port;
382
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;
387
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))) {
393                     break;
394                 }
395             }
396             if ( iface == 0 ) {
397                 return 0;
398             }
399             for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
400                 if ( ap->ap_packet == nbp_packet ) {
401                     break;
402                 }
403             }
404
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) );
408             }
409
410             locallkup = 1;
411         } else {
412 #ifdef BSD4_4
413             sat.sat_len = sizeof( struct sockaddr_at );
414 #endif /* BSD4_4 */
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;
419
420                 if ( rtmp->rt_gate == 0 ) {
421                     for ( iface = interfaces; iface;
422                             iface = iface->i_next ) {
423                         if ( iface->i_rt == rtmp ) {
424                             break;
425                         }
426                     }
427                     if ( !iface ) {
428                         syslog( LOG_ERR, "nbp_packet: \
429 Can't find route's interface!" );
430                         return -1;
431                     }
432                     ap = iface->i_ports;
433                 } else {
434                     ap = rtmp->rt_gate->g_iface->i_ports;
435                 }
436                 for ( ; ap; ap = ap->ap_next ) {
437                     if ( ap->ap_packet == nbp_packet ) {
438                         break;
439                     }
440                 }
441                 if ( !ap ) {
442                     syslog( LOG_ERR, "nbp_packet: Can't find port!" );
443                     return -1;
444                 }
445
446                 if ( transition &&
447                         ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
448                     if ( rtmp->rt_gate == 0 ) {
449                         locallkup = 1;
450                     }
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;
455                 } else {
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;
461                         locallkup = 1;
462                     } else {
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;
467                     }
468                 }
469
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,
475                             strerror(errno) );
476                     continue;
477                 }
478             }
479         }
480
481         if ( !locallkup ) {
482             break;
483         }
484         /*FALL THROUGH*/
485
486     case NBPOP_FWD :
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,
497                         strerror(errno) );
498                 return 0;
499             }
500         }
501         /*FALL THROUGH*/
502
503     case NBPOP_LKUP :
504         /* search our data */
505         n = i = 0;
506         data = packet + 1 + SZ_NBPHDR;
507         end = packet + sizeof( packet );
508
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) {
513               continue;
514             }
515
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,
519                         nn.nn_objlen )) {
520                     continue;
521                 }
522             }
523
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,
527                         nn.nn_typelen )) {
528                     continue;
529                 }
530             }
531
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->
539                                 rt_zt->l_data;
540                         if ( zt->zt_len != nn.nn_zonelen ||
541                                 strndiacasecmp( zt->zt_name, nn.nn_zone,
542                                 zt->zt_len )) {
543                             continue;
544                         }
545                     }
546                 } else {
547                     if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
548                             strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
549                             nn.nn_zonelen )) {
550                         continue;
551                     }
552                 }
553             }
554
555             /*
556              * Another tuple won't fit. Send what we've already
557              * got, and start the next packet.
558              */
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;
562                 nh.nh_cnt = n;
563                 cc = data - packet;
564                 data = packet;
565                 *data++ = DDPTYPE_NBP;
566                 memcpy( data, &nh, SZ_NBPHDR );
567
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,
574                             strerror(errno) );
575                     return 0;
576                 }
577
578                 n = 0;
579                 data = packet + 1 + SZ_NBPHDR;
580                 end = packet + sizeof( packet );
581             }
582
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;
586             /*
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
591              * is fixed.
592              */
593             nt.nt_enum = i++;
594
595             memcpy( data, &nt, SZ_NBPTUPLE );
596             data += SZ_NBPTUPLE;
597
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;
601
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;
605
606             /*
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?
610              */
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;
615             } else {
616                 *data++ = 1;
617                 *data++ = '*';
618             }
619
620             n++;
621         }
622
623         if ( n != 0 ) {
624             nh.nh_op = NBPOP_LKUPREPLY;
625             nh.nh_cnt = n;
626             cc = data - packet;
627             data = packet;
628             *data++ = DDPTYPE_NBP;
629             memcpy( data, &nh, SZ_NBPHDR );
630
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,
637                         strerror(errno) );
638                 return 0;
639             }
640         }
641         break;
642
643     default :
644         syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );
645         return 1;
646     }
647
648     return 0;
649 }