]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/nbp.c
CVS id tags, define fixes, code beautification
[netatalk.git] / etc / atalkd / nbp.c
1 /*
2  * $Id: nbp.c,v 1.3 2001-06-25 20:13:45 rufustfirefly 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 #include <net/if.h>
20 #include <netatalk/at.h>
21 #include <atalk/ddp.h>
22 #include <atalk/atp.h>
23 #include <atalk/nbp.h>
24 #include <atalk/util.h>
25
26 #ifdef __svr4__
27 #include <sys/sockio.h>
28 #endif /* __svr4__ */
29
30 #include "atserv.h"
31 #include "interface.h"
32 #include "list.h"
33 #include "rtmp.h"
34 #include "gate.h"
35 #include "zip.h"
36 #include "nbp.h"
37 #include "multicast.h"
38
39 extern int      transition;
40
41 struct nbptab   *nbptab = NULL;
42
43 static 
44 void nbp_ack( fd, nh_op, nh_id, to )
45     int                 fd;
46     int                 nh_op;
47     int                 nh_id;
48     struct sockaddr_at  *to;
49 {
50     struct nbphdr       nh;
51     char                *data, packet[ SZ_NBPHDR + 1 ];
52
53     nh.nh_op = nh_op;
54     nh.nh_cnt = 0;
55     nh.nh_id = nh_id;
56     data = packet;
57     *data++ = DDPTYPE_NBP;
58     bcopy( &nh, data, SZ_NBPHDR );
59     data += SZ_NBPHDR;
60     if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
61             sizeof( struct sockaddr_at )) < 0 ) {
62         syslog( LOG_ERR, "sendto: %m" );
63     }
64 }
65
66 int nbp_packet( ap, from, data, len )
67     struct atport       *ap;
68     struct sockaddr_at  *from;
69     char                *data;
70     int                 len;
71 {
72     struct nbphdr       nh;
73     struct nbptuple     nt;
74     struct nbpnve       nn;
75     struct sockaddr_at  sat;
76     struct nbptab       *ntab;
77     struct ziptab       *zt;
78     struct interface    *iface;
79     struct list         *l;
80     struct rtmptab      *rtmp;
81     char                *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
82     int                 n, i, cc, locallkup;
83
84     end = data + len;
85     if ( data >= end ) {
86         syslog( LOG_INFO, "nbp_packet malformed packet" );
87         return 1;
88     }
89     if ( *data++ != DDPTYPE_NBP ) {
90         syslog( LOG_INFO, "nbp_packet bad ddp type" );
91         return 1;
92     }
93
94     if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
95         syslog( LOG_INFO, "nbp_packet: malformed packet" );
96         return 1;
97     }
98     memcpy( &nh, data, SZ_NBPHDR );
99     nbpop = data;                       /* remember for fwd and brrq */
100     data += SZ_NBPHDR;
101     if ( nh.nh_cnt != 1 ) {
102         syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
103                 nh.nh_op );
104         return 1;
105     }
106
107     memcpy( &nt, data, SZ_NBPTUPLE );
108     data += SZ_NBPTUPLE;
109
110     memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
111 #ifdef BSD4_4
112     nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
113 #endif /* BSD4_4 */
114     nn.nn_sat.sat_family = AF_APPLETALK;
115     nn.nn_sat.sat_addr.s_net = nt.nt_net;
116     nn.nn_sat.sat_addr.s_node = nt.nt_node;
117     nn.nn_sat.sat_port = nt.nt_port;
118
119     /* object */
120     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
121         syslog( LOG_INFO, "nbp_packet: malformed packet" );
122         return 1;
123     }
124     nn.nn_objlen = *data++;
125     memcpy( nn.nn_obj, data, nn.nn_objlen );
126     data += nn.nn_objlen;
127
128     /* type */
129     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
130         syslog( LOG_INFO, "nbp_packet: malformed packet" );
131         return 1;
132     }
133     nn.nn_typelen = *data++;
134     memcpy( nn.nn_type, data, nn.nn_typelen );
135     data += nn.nn_typelen;
136
137     /* zone */
138     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
139         syslog( LOG_INFO, "nbp_packet: malformed packet" );
140         return 1;
141     }
142     zonep = data;                       /* remember for fwd */
143     nn.nn_zonelen = *data++;
144     memcpy( nn.nn_zone, data, nn.nn_zonelen );
145     data += nn.nn_zonelen;
146
147     if ( data != end ) {
148         syslog( LOG_INFO, "nbp_packet: malformed packet" );
149         return 1;
150     }
151
152     locallkup = 0;
153     switch ( nh.nh_op ) {
154
155     case NBPOP_RGSTR :
156         /*
157          * Find the ziptab entry for the zone we're trying to register in.
158          */
159         if ( nn.nn_zonelen == 0 ||
160                 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
161             if ( interfaces->i_next->i_rt->rt_zt ) {
162                 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
163             } else {
164                 zt = 0;
165             }
166         } else {
167             for ( zt = ziptab; zt; zt = zt->zt_next ) {
168                 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
169                         nn.nn_zone, zt->zt_len ) == 0 ) {
170                     break;
171                 }
172             }
173             if ( zt == 0 ) {
174                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
175                 return 0;
176             }
177         }
178
179         /*
180          * Observe that we don't have to do any local-zone verification
181          * if the zone aleady has a multicast address set.
182          */
183         if ( zt != 0 && zt->zt_bcast == 0 ) {
184             /*
185              * Check if zone is associated with any of our local interfaces.
186              */
187             for ( iface = interfaces; iface; iface = iface->i_next ) {
188                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
189                     if ( zt == (struct ziptab *)l->l_data ) {
190                         break;
191                     }
192                 }
193                 if ( l != 0 ) {
194                     break;
195                 }
196             }
197             if ( iface == 0 ) {
198                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
199                 return 0;
200             }
201
202             /* calculate and save multicast address */
203             if (zone_bcast(zt) < 0) {
204                 syslog(LOG_ERR, "nbp_packet: zone_bcast");
205                 return -1;
206             }
207
208             for ( iface = interfaces; iface; iface = iface->i_next ) {
209                 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
210                     continue;
211                 }
212                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
213                     if ( zt == (struct ziptab *)l->l_data ) {
214                         /* add multicast */
215                         if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
216                             syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
217                             return -1;
218                         }
219                     }
220                 }
221             }
222         }
223
224         if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
225                 == 0 ) {
226             syslog( LOG_ERR, "nbp_packet: malloc: %m" );
227             return -1;
228         }
229         memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
230         ntab->nt_iface = ap->ap_iface;
231         ntab->nt_next = nbptab;
232         ntab->nt_prev = 0;
233         if ( nbptab ) {
234             nbptab->nt_prev = ntab;
235         }
236         nbptab = ntab;
237
238         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
239         break;
240
241     case NBPOP_UNRGSTR :
242         /* deal with local zone info */
243         if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
244             ( nn.nn_zonelen == 0 )) {
245           locallkup = 1;
246           if ( interfaces->i_next->i_rt->rt_zt ) {
247             zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
248           } else {
249             zt = NULL;
250           }
251         }
252
253         /* remove from our data, perhaps removing a multicast address */
254         for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
255             if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
256                     strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
257                     nn.nn_objlen )) {
258                 continue;
259             }
260             if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
261                     strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
262                     nn.nn_typelen )) {
263                 continue;
264             }
265             /*
266              * I *think* we really do check the zone, here.
267              *
268              * i changed it to better handle local zone cases as well.
269              * -- asun
270              */
271             
272             /* match local zones */
273             if (locallkup) {
274               /* ntab is also local zone */
275               if (( ntab->nt_nve.nn_zonelen == 1 &&
276                     *ntab->nt_nve.nn_zone == '*' ) || 
277                   (ntab->nt_nve.nn_zonelen == 0))
278                 break;
279               
280               /* ntab is default zone */
281               if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
282                   (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
283                                   zt->zt_len) == 0)) {
284                 break;
285               }
286             }
287             
288             /* match particular zone */
289             if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
290                 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
291                                 nn.nn_zonelen ) == 0)) {
292                 break;
293             }
294         }
295         if ( ntab == 0 ) {
296             nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
297             return 0;
298         }
299
300         if ( ntab->nt_next != 0 ) {
301             ntab->nt_next->nt_prev = ntab->nt_prev;
302         }
303         if ( ntab->nt_prev != 0 ) {
304             ntab->nt_prev->nt_next = ntab->nt_next;
305         }
306         if ( ntab == nbptab ) {
307             nbptab = ntab->nt_next;
308         }
309
310         /*
311          * Check for another nbptab entry with the same zone.  If
312          * there isn't one, find the ziptab entry for the zone and
313          * remove the multicast address from the appropriate interfaces.
314          * XXX
315          */
316
317         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
318         break;
319
320     case NBPOP_BRRQ :
321         /*
322          * Couple of things:  1. Unless we have the -t flag (which is sort
323          * of a misnomer, since you need it if you're doing any phase 1
324          * work), always send NBPOP_FWD.  2. If we get a zone of '*',
325          * and we know what the sender meant by '*', we copy the real
326          * zone into the packet.
327          */
328         if ( nn.nn_zonelen == 0 ||
329                 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
330             iface = ap->ap_iface;
331             if ( iface && iface->i_rt->rt_zt ) {
332                 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
333             } else if ( interfaces->i_next->i_rt->rt_zt ) {
334                 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
335             } else {
336                 zt = NULL;
337             }
338
339             /*
340              * Copy zone into packet.  Note that we're changing len, data, and
341              * nbpop.  Later, we'll use ( data - len ) to mean the beginning
342              * of this packet.
343              */
344             if ( zt ) {
345                 memcpy( packet, data - len, len );
346                 nbpop = packet + ( len - ( data - nbpop ));
347                 data = packet + ( len - ( data - zonep ));
348                 *data++ = zt->zt_len;
349                 memcpy( data, zt->zt_name, zt->zt_len );
350                 data += zt->zt_len;
351                 len = data - packet;
352             }
353         } else {
354             for ( zt = ziptab; zt; zt = zt->zt_next ) {
355                 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
356                         nn.nn_zone, zt->zt_len ) == 0 ) {
357                     break;
358                 }
359             }
360             if ( zt == 0 ) {
361                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
362                 return 0;
363             }
364         }
365
366         /*
367          * If we've got no zones, send out LKUP on the local net.
368          * Otherwise, look through the zone table.
369          */
370         if ( zt == 0 ) {
371 #ifdef BSD4_4
372             sat.sat_len = sizeof( struct sockaddr_at );
373 #endif /* BSD4_4 */
374             sat.sat_family = AF_APPLETALK;
375             sat.sat_port = ap->ap_port;
376
377             nh.nh_op = NBPOP_LKUP;
378             memcpy( nbpop, &nh, SZ_NBPHDR );
379             sat.sat_addr.s_net = 0;                     /* XXX */
380             sat.sat_addr.s_node = ATADDR_BCAST;
381
382             /* Find the first non-loopback ap */
383             for ( iface = interfaces; iface; iface = iface->i_next ) {
384                 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
385                     (iface == ap->ap_iface || 
386                     (iface->i_flags & IFACE_ISROUTER))) {
387                     break;
388                 }
389             }
390             if ( iface == 0 ) {
391                 return 0;
392             }
393             for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
394                 if ( ap->ap_packet == nbp_packet ) {
395                     break;
396                 }
397             }
398
399             if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
400                     sizeof( struct sockaddr_at )) < 0 ) {
401                 syslog( LOG_ERR, "nbp brrq sendto: %m" );
402             }
403
404             locallkup = 1;
405         } else {
406 #ifdef BSD4_4
407             sat.sat_len = sizeof( struct sockaddr_at );
408 #endif /* BSD4_4 */
409             sat.sat_family = AF_APPLETALK;
410             sat.sat_port = ap->ap_port;
411             for ( l = zt->zt_rt; l; l = l->l_next ) {
412                 rtmp = (struct rtmptab *)l->l_data;
413
414                 if ( rtmp->rt_gate == 0 ) {
415                     for ( iface = interfaces; iface;
416                             iface = iface->i_next ) {
417                         if ( iface->i_rt == rtmp ) {
418                             break;
419                         }
420                     }
421                     if ( !iface ) {
422                         syslog( LOG_ERR, "nbp_packet: \
423 Can't find route's interface!" );
424                         return -1;
425                     }
426                     ap = iface->i_ports;
427                 } else {
428                     ap = rtmp->rt_gate->g_iface->i_ports;
429                 }
430                 for ( ; ap; ap = ap->ap_next ) {
431                     if ( ap->ap_packet == nbp_packet ) {
432                         break;
433                     }
434                 }
435                 if ( !ap ) {
436                     syslog( LOG_ERR, "nbp_packet: Can't find port!" );
437                     return -1;
438                 }
439
440                 if ( transition &&
441                         ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
442                     if ( rtmp->rt_gate == 0 ) {
443                         locallkup = 1;
444                     }
445                     nh.nh_op = NBPOP_LKUP;
446                     bcopy( &nh, nbpop, SZ_NBPHDR );
447                     sat.sat_addr.s_net = rtmp->rt_firstnet;
448                     sat.sat_addr.s_node = ATADDR_BCAST;
449                 } else {
450                     if ( rtmp->rt_gate == 0 ) {
451                         nh.nh_op = NBPOP_LKUP;
452                         bcopy( &nh, nbpop, SZ_NBPHDR );
453                         sat.sat_addr.s_net = 0;
454                         sat.sat_addr.s_node = ATADDR_BCAST;
455                         locallkup = 1;
456                     } else {
457                         nh.nh_op = NBPOP_FWD;
458                         bcopy( &nh, nbpop, SZ_NBPHDR );
459                         sat.sat_addr.s_net = rtmp->rt_firstnet;
460                         sat.sat_addr.s_node = 0;
461                     }
462                 }
463
464                 if ( sendto( ap->ap_fd, data - len, len, 0,
465                         (struct sockaddr *)&sat,
466                         sizeof( struct sockaddr_at )) < 0 ) {
467                     syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
468                             ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
469                     continue;
470                 }
471             }
472         }
473
474         if ( !locallkup ) {
475             break;
476         }
477         /*FALL THROUGH*/
478
479     case NBPOP_FWD :
480         /* send lkup on net. we need to make sure we're a router. */
481         if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
482             nh.nh_op = NBPOP_LKUP;
483             bcopy( &nh, nbpop, SZ_NBPHDR );
484             from->sat_addr.s_net = 0;
485             from->sat_addr.s_node = ATADDR_BCAST;
486             if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
487                     sizeof( struct sockaddr_at )) < 0 ) {
488                 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
489                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
490                 return 0;
491             }
492         }
493         /*FALL THROUGH*/
494
495     case NBPOP_LKUP :
496         /* search our data */
497         n = i = 0;
498         data = packet + 1 + SZ_NBPHDR;
499         end = packet + sizeof( packet );
500
501         for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
502             /* don't send out entries if we don't want to route. */
503             if ((ap->ap_iface != ntab->nt_iface) && 
504                 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
505               continue;
506             }
507
508             if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
509                 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
510                         strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
511                         nn.nn_objlen )) {
512                     continue;
513                 }
514             }
515
516             if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
517                 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
518                         strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
519                         nn.nn_typelen )) {
520                     continue;
521                 }
522             }
523
524             if ( nn.nn_zonelen != 0 &&
525                     ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
526                 if ( ntab->nt_nve.nn_zonelen == 0 ||
527                         ( ntab->nt_nve.nn_zonelen == 1 &&
528                         *ntab->nt_nve.nn_zone == '*' )) {
529                     if ( interfaces->i_next->i_rt->rt_zt ) {
530                         zt = (struct ziptab *)interfaces->i_next->i_rt->
531                                 rt_zt->l_data;
532                         if ( zt->zt_len != nn.nn_zonelen ||
533                                 strndiacasecmp( zt->zt_name, nn.nn_zone,
534                                 zt->zt_len )) {
535                             continue;
536                         }
537                     }
538                 } else {
539                     if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
540                             strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
541                             nn.nn_zonelen )) {
542                         continue;
543                     }
544                 }
545             }
546
547             /*
548              * Another tuple won't fit. Send what we've already
549              * got, and start the next packet.
550              */
551             if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
552                     ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
553                 nh.nh_op = NBPOP_LKUPREPLY;
554                 nh.nh_cnt = n;
555                 cc = data - packet;
556                 data = packet;
557                 *data++ = DDPTYPE_NBP;
558                 bcopy( &nh, data, SZ_NBPHDR );
559
560                 if ( sendto( ap->ap_fd, packet, cc, 0,
561                         (struct sockaddr *)&nn.nn_sat,
562                         sizeof( struct sockaddr_at )) < 0 ) {
563                     syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
564                             ntohs( nn.nn_sat.sat_addr.s_net ),
565                             nn.nn_sat.sat_addr.s_node );
566                     return 0;
567                 }
568
569                 n = 0;
570                 data = packet + 1 + SZ_NBPHDR;
571                 end = packet + sizeof( packet );
572             }
573
574             nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
575             nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
576             nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
577             /*
578              * Right now, we'll just give each name a unique enum.  In
579              * the future, we might need to actually assign and save
580              * an enum, based on the associated address.  For the moment,
581              * the enums will be unique and constant, since the order
582              * is fixed.
583              */
584             nt.nt_enum = i++;
585
586             memcpy( data, &nt, SZ_NBPTUPLE );
587             data += SZ_NBPTUPLE;
588
589             *data++ = ntab->nt_nve.nn_objlen;
590             memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
591             data += ntab->nt_nve.nn_objlen;
592
593             *data++ = ntab->nt_nve.nn_typelen;
594             memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
595             data += ntab->nt_nve.nn_typelen;
596
597             /*
598              * Macs won't see something with a zone of 0 length.  We
599              * will always return '*' instead.  Perhaps we should
600              * unconditionally return the real zone?
601              */
602             if ( ntab->nt_nve.nn_zonelen ) {
603                 *data++ = ntab->nt_nve.nn_zonelen;
604                 bcopy( ntab->nt_nve.nn_zone, data, ntab->nt_nve.nn_zonelen );
605                 data += ntab->nt_nve.nn_zonelen;
606             } else {
607                 *data++ = 1;
608                 *data++ = '*';
609             }
610
611             n++;
612         }
613
614         if ( n != 0 ) {
615             nh.nh_op = NBPOP_LKUPREPLY;
616             nh.nh_cnt = n;
617             cc = data - packet;
618             data = packet;
619             *data++ = DDPTYPE_NBP;
620             bcopy( &nh, data, SZ_NBPHDR );
621
622             if ( sendto( ap->ap_fd, packet, cc, 0,
623                     (struct sockaddr *)&nn.nn_sat,
624                     sizeof( struct sockaddr_at )) < 0 ) {
625                 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
626                         ntohs( nn.nn_sat.sat_addr.s_net ),
627                         nn.nn_sat.sat_addr.s_node );
628                 return 0;
629             }
630         }
631         break;
632
633     default :
634         syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );
635         return 1;
636     }
637
638     return 0;
639 }