]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/nbp.c
AC_HEADER_STDC autoconf change
[netatalk.git] / etc / atalkd / nbp.c
1 /*
2  * $Id: nbp.c,v 1.5 2001-08-15 01:39:39 srittau 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 <sys/syslog.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
19 #ifdef TRU64
20 #include <sys/mbuf.h>
21 #include <net/route.h>
22 #endif /* TRU64 */
23 #include <net/if.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>
29
30 #ifdef __svr4__
31 #include <sys/sockio.h>
32 #endif /* __svr4__ */
33
34 #include "atserv.h"
35 #include "interface.h"
36 #include "list.h"
37 #include "rtmp.h"
38 #include "gate.h"
39 #include "zip.h"
40 #include "nbp.h"
41 #include "multicast.h"
42
43 extern int      transition;
44
45 struct nbptab   *nbptab = NULL;
46
47 static 
48 void nbp_ack( fd, nh_op, nh_id, to )
49     int                 fd;
50     int                 nh_op;
51     int                 nh_id;
52     struct sockaddr_at  *to;
53 {
54     struct nbphdr       nh;
55     char                *data, packet[ SZ_NBPHDR + 1 ];
56
57     nh.nh_op = nh_op;
58     nh.nh_cnt = 0;
59     nh.nh_id = nh_id;
60     data = packet;
61     *data++ = DDPTYPE_NBP;
62     memcpy( data, &nh, SZ_NBPHDR );
63     data += 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" );
67     }
68 }
69
70 int nbp_packet( ap, from, data, len )
71     struct atport       *ap;
72     struct sockaddr_at  *from;
73     char                *data;
74     int                 len;
75 {
76     struct nbphdr       nh;
77     struct nbptuple     nt;
78     struct nbpnve       nn;
79     struct sockaddr_at  sat;
80     struct nbptab       *ntab;
81     struct ziptab       *zt;
82     struct interface    *iface;
83     struct list         *l;
84     struct rtmptab      *rtmp;
85     char                *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
86     int                 n, i, cc, locallkup;
87
88     end = data + len;
89     if ( data >= end ) {
90         syslog( LOG_INFO, "nbp_packet malformed packet" );
91         return 1;
92     }
93     if ( *data++ != DDPTYPE_NBP ) {
94         syslog( LOG_INFO, "nbp_packet bad ddp type" );
95         return 1;
96     }
97
98     if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
99         syslog( LOG_INFO, "nbp_packet: malformed packet" );
100         return 1;
101     }
102     memcpy( &nh, data, SZ_NBPHDR );
103     nbpop = data;                       /* remember for fwd and brrq */
104     data += SZ_NBPHDR;
105     if ( nh.nh_cnt != 1 ) {
106         syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
107                 nh.nh_op );
108         return 1;
109     }
110
111     memcpy( &nt, data, SZ_NBPTUPLE );
112     data += SZ_NBPTUPLE;
113
114     memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
115 #ifdef BSD4_4
116     nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
117 #endif /* BSD4_4 */
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;
122
123     /* object */
124     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
125         syslog( LOG_INFO, "nbp_packet: malformed packet" );
126         return 1;
127     }
128     nn.nn_objlen = *data++;
129     memcpy( nn.nn_obj, data, nn.nn_objlen );
130     data += nn.nn_objlen;
131
132     /* type */
133     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
134         syslog( LOG_INFO, "nbp_packet: malformed packet" );
135         return 1;
136     }
137     nn.nn_typelen = *data++;
138     memcpy( nn.nn_type, data, nn.nn_typelen );
139     data += nn.nn_typelen;
140
141     /* zone */
142     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
143         syslog( LOG_INFO, "nbp_packet: malformed packet" );
144         return 1;
145     }
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;
150
151     if ( data != end ) {
152         syslog( LOG_INFO, "nbp_packet: malformed packet" );
153         return 1;
154     }
155
156     locallkup = 0;
157     switch ( nh.nh_op ) {
158
159     case NBPOP_RGSTR :
160         /*
161          * Find the ziptab entry for the zone we're trying to register in.
162          */
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;
167             } else {
168                 zt = 0;
169             }
170         } else {
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 ) {
174                     break;
175                 }
176             }
177             if ( zt == 0 ) {
178                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
179                 return 0;
180             }
181         }
182
183         /*
184          * Observe that we don't have to do any local-zone verification
185          * if the zone aleady has a multicast address set.
186          */
187         if ( zt != 0 && zt->zt_bcast == 0 ) {
188             /*
189              * Check if zone is associated with any of our local interfaces.
190              */
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 ) {
194                         break;
195                     }
196                 }
197                 if ( l != 0 ) {
198                     break;
199                 }
200             }
201             if ( iface == 0 ) {
202                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
203                 return 0;
204             }
205
206             /* calculate and save multicast address */
207             if (zone_bcast(zt) < 0) {
208                 syslog(LOG_ERR, "nbp_packet: zone_bcast");
209                 return -1;
210             }
211
212             for ( iface = interfaces; iface; iface = iface->i_next ) {
213                 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
214                     continue;
215                 }
216                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
217                     if ( zt == (struct ziptab *)l->l_data ) {
218                         /* add multicast */
219                         if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
220                             syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
221                             return -1;
222                         }
223                     }
224                 }
225             }
226         }
227
228         if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
229                 == 0 ) {
230             syslog( LOG_ERR, "nbp_packet: malloc: %m" );
231             return -1;
232         }
233         memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
234         ntab->nt_iface = ap->ap_iface;
235         ntab->nt_next = nbptab;
236         ntab->nt_prev = 0;
237         if ( nbptab ) {
238             nbptab->nt_prev = ntab;
239         }
240         nbptab = ntab;
241
242         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
243         break;
244
245     case NBPOP_UNRGSTR :
246         /* deal with local zone info */
247         if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
248             ( nn.nn_zonelen == 0 )) {
249           locallkup = 1;
250           if ( interfaces->i_next->i_rt->rt_zt ) {
251             zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
252           } else {
253             zt = NULL;
254           }
255         }
256
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,
261                     nn.nn_objlen )) {
262                 continue;
263             }
264             if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
265                     strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
266                     nn.nn_typelen )) {
267                 continue;
268             }
269             /*
270              * I *think* we really do check the zone, here.
271              *
272              * i changed it to better handle local zone cases as well.
273              * -- asun
274              */
275             
276             /* match local zones */
277             if (locallkup) {
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))
282                 break;
283               
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,
287                                   zt->zt_len) == 0)) {
288                 break;
289               }
290             }
291             
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)) {
296                 break;
297             }
298         }
299         if ( ntab == 0 ) {
300             nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
301             return 0;
302         }
303
304         if ( ntab->nt_next != 0 ) {
305             ntab->nt_next->nt_prev = ntab->nt_prev;
306         }
307         if ( ntab->nt_prev != 0 ) {
308             ntab->nt_prev->nt_next = ntab->nt_next;
309         }
310         if ( ntab == nbptab ) {
311             nbptab = ntab->nt_next;
312         }
313
314         /*
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.
318          * XXX
319          */
320
321         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
322         break;
323
324     case NBPOP_BRRQ :
325         /*
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.
331          */
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;
339             } else {
340                 zt = NULL;
341             }
342
343             /*
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
346              * of this packet.
347              */
348             if ( zt ) {
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 );
354                 data += zt->zt_len;
355                 len = data - packet;
356             }
357         } else {
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 ) {
361                     break;
362                 }
363             }
364             if ( zt == 0 ) {
365                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
366                 return 0;
367             }
368         }
369
370         /*
371          * If we've got no zones, send out LKUP on the local net.
372          * Otherwise, look through the zone table.
373          */
374         if ( zt == 0 ) {
375 #ifdef BSD4_4
376             sat.sat_len = sizeof( struct sockaddr_at );
377 #endif /* BSD4_4 */
378             sat.sat_family = AF_APPLETALK;
379             sat.sat_port = ap->ap_port;
380
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;
385
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))) {
391                     break;
392                 }
393             }
394             if ( iface == 0 ) {
395                 return 0;
396             }
397             for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
398                 if ( ap->ap_packet == nbp_packet ) {
399                     break;
400                 }
401             }
402
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" );
406             }
407
408             locallkup = 1;
409         } else {
410 #ifdef BSD4_4
411             sat.sat_len = sizeof( struct sockaddr_at );
412 #endif /* BSD4_4 */
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;
417
418                 if ( rtmp->rt_gate == 0 ) {
419                     for ( iface = interfaces; iface;
420                             iface = iface->i_next ) {
421                         if ( iface->i_rt == rtmp ) {
422                             break;
423                         }
424                     }
425                     if ( !iface ) {
426                         syslog( LOG_ERR, "nbp_packet: \
427 Can't find route's interface!" );
428                         return -1;
429                     }
430                     ap = iface->i_ports;
431                 } else {
432                     ap = rtmp->rt_gate->g_iface->i_ports;
433                 }
434                 for ( ; ap; ap = ap->ap_next ) {
435                     if ( ap->ap_packet == nbp_packet ) {
436                         break;
437                     }
438                 }
439                 if ( !ap ) {
440                     syslog( LOG_ERR, "nbp_packet: Can't find port!" );
441                     return -1;
442                 }
443
444                 if ( transition &&
445                         ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
446                     if ( rtmp->rt_gate == 0 ) {
447                         locallkup = 1;
448                     }
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;
453                 } else {
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;
459                         locallkup = 1;
460                     } else {
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;
465                     }
466                 }
467
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 );
473                     continue;
474                 }
475             }
476         }
477
478         if ( !locallkup ) {
479             break;
480         }
481         /*FALL THROUGH*/
482
483     case NBPOP_FWD :
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 );
494                 return 0;
495             }
496         }
497         /*FALL THROUGH*/
498
499     case NBPOP_LKUP :
500         /* search our data */
501         n = i = 0;
502         data = packet + 1 + SZ_NBPHDR;
503         end = packet + sizeof( packet );
504
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) {
509               continue;
510             }
511
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,
515                         nn.nn_objlen )) {
516                     continue;
517                 }
518             }
519
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,
523                         nn.nn_typelen )) {
524                     continue;
525                 }
526             }
527
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->
535                                 rt_zt->l_data;
536                         if ( zt->zt_len != nn.nn_zonelen ||
537                                 strndiacasecmp( zt->zt_name, nn.nn_zone,
538                                 zt->zt_len )) {
539                             continue;
540                         }
541                     }
542                 } else {
543                     if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
544                             strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
545                             nn.nn_zonelen )) {
546                         continue;
547                     }
548                 }
549             }
550
551             /*
552              * Another tuple won't fit. Send what we've already
553              * got, and start the next packet.
554              */
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;
558                 nh.nh_cnt = n;
559                 cc = data - packet;
560                 data = packet;
561                 *data++ = DDPTYPE_NBP;
562                 memcpy( data, &nh, SZ_NBPHDR );
563
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 );
570                     return 0;
571                 }
572
573                 n = 0;
574                 data = packet + 1 + SZ_NBPHDR;
575                 end = packet + sizeof( packet );
576             }
577
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;
581             /*
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
586              * is fixed.
587              */
588             nt.nt_enum = i++;
589
590             memcpy( data, &nt, SZ_NBPTUPLE );
591             data += SZ_NBPTUPLE;
592
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;
596
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;
600
601             /*
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?
605              */
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;
610             } else {
611                 *data++ = 1;
612                 *data++ = '*';
613             }
614
615             n++;
616         }
617
618         if ( n != 0 ) {
619             nh.nh_op = NBPOP_LKUPREPLY;
620             nh.nh_cnt = n;
621             cc = data - packet;
622             data = packet;
623             *data++ = DDPTYPE_NBP;
624             memcpy( data, &nh, SZ_NBPHDR );
625
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 );
632                 return 0;
633             }
634         }
635         break;
636
637     default :
638         syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );
639         return 1;
640     }
641
642     return 0;
643 }