]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/ddp_nbp.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / netat / ddp_nbp.c
1 /*
2 * Copyright (c) 1998-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
30 */
31
32 #include <string.h>
33
34 #include <sys/errno.h>
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <machine/spl.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/proc.h>
41 #include <sys/filedesc.h>
42 #include <sys/fcntl.h>
43 #include <sys/mbuf.h>
44 #include <sys/ioctl.h>
45 #include <sys/malloc.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48
49 #include <net/if.h>
50 #include <net/if_types.h>
51
52 #include <netat/sysglue.h>
53 #include <netat/appletalk.h>
54 #include <netat/at_pcb.h>
55 #include <netat/at_var.h>
56 #include <netat/ddp.h>
57 #include <netat/nbp.h>
58 #include <netat/zip.h>
59 #include <netat/rtmp.h>
60 #include <netat/routing_tables.h> /* router */
61 #include <netat/at_snmp.h>
62 #include <netat/debug.h>
63
64 /* reaching for DDP and NBP headers in the datagram */
65 #define DATA_DDP(mp) ((at_ddp_t *)(gbuf_rptr(mp)))
66 #define DATA_NBP(mp) ((at_nbp_t *)((DATA_DDP(mp))->data))
67
68 /* Get to the nve_entry_t part ofthe buffer */
69 #define NVE_ENTRY(mp) (nve_entry_t *)(gbuf_rptr(mp))
70
71 #ifndef MIN
72 #define MIN(a,b) ((a)>(b)?(b):(a))
73 #endif
74
75 #define errno nbperrno
76
77 /* externs */
78 extern at_ifaddr_t *ifID_table[];
79 extern at_ifaddr_t *ifID_home;
80
81 TAILQ_HEAD(name_registry, _nve_) name_registry;
82
83
84 /* statics */
85 static int errno;
86 static gbuf_t *lzones=0; /* head of local zones list */
87 static int lzonecnt=0; /* # zones stored in lzones */
88 static u_int hzonehash=0; /* hash val of home zone */
89
90 static int nbp_lkup_reply(nbp_req_t *, nve_entry_t *);
91 static int nbp_strcmp(at_nvestr_t *, at_nvestr_t *, u_char);
92 static int nbp_setup_resp(nbp_req_t *, int);
93 static int nbp_send_resp(nbp_req_t *);
94 static int nbp_validate_n_hash(nbp_req_t *, int, int);
95 static nve_entry_t *nbp_search_nve(nbp_req_t *, at_ifaddr_t *);
96 static int isZoneLocal(at_nvestr_t *);
97 static int nbp_enum_gen (nve_entry_t *);
98 static void nbp_setup_hdr (nbp_req_t *);
99 static void nbp_upshift (u_char *, int);
100 static u_char *nbp2zone(at_nbp_t *, u_char *);
101
102 /* macros */
103 #define NVE_LOCK nve_lock
104
105
106 static long nbp_id_count = 0;
107
108 void sethzonehash(elapp)
109 at_ifaddr_t *elapp;
110 {
111 if (elapp->startup_zone.len) {
112 hzonehash = nbp_strhash(&elapp->startup_zone);
113 }
114 }
115
116 void nbp_shutdown(void)
117 {
118 /* delete all NVE's and release buffers */
119 register nve_entry_t *nve_entry, *nve_next;
120
121 for ((nve_entry = TAILQ_FIRST(&name_registry)); nve_entry; nve_entry = nve_next) {
122 nve_next = TAILQ_NEXT(nve_entry, nve_link);
123
124 /* NB: nbp_delete_entry calls TAILQ_REMOVE */
125 nbp_delete_entry(nve_entry);
126 }
127
128 if (lzones) {
129 gbuf_freem(lzones);
130 lzonecnt = 0;
131 lzones = NULL;
132 }
133 } /* nbp_shutdown */
134
135 static
136 u_char *nbp2zone(nbp, maxp)
137 at_nbp_t *nbp;
138 u_char *maxp;
139 {
140
141 u_char *p;
142
143 p = (u_char*)&nbp->tuple[0].enu_entity; /* p -> object */
144 if (p >= maxp) return NULL;
145 p += (*p +1); /* p -> type */
146 if (p >= maxp) return NULL;
147 p += (*p +1); /* p -> zone */
148 if (p >= maxp) return NULL;
149 if ((p + *p) >= maxp) return NULL;
150 return(p);
151 }
152
153 void nbp_input(m, ifID)
154 register gbuf_t *m;
155 register at_ifaddr_t *ifID;
156
157 {
158 register at_ddp_t *ddp = DATA_DDP(m);
159 register at_nbp_t *nbp = DATA_NBP(m);
160 register RT_entry *rt;
161 register int ddpSent = FALSE; /* true if we re-sent this pkt (don't free) */
162 struct etalk_addr mcastAddr;
163 nbp_req_t nbp_req;
164 u_char *p;
165
166 /* from original nbp_input() when this function was nbp_handler() */
167 if ((gbuf_type(m) != MT_DATA && gbuf_type(m) != MSG_DATA) ||
168 ddp->type != DDP_NBP) {
169 gbuf_freem(m);
170 return;
171 }
172
173 /* Some initializations */
174 nbp_req.response = NULL;
175 nbp_req.request = m;
176 nbp_req.space_unused = nbp_req.flags = 0;
177
178 dPrintf(D_M_NBP_LOW, D_L_USR1,
179 ("nbp_input control:%d tuplecount:%d id:%d\n",
180 nbp->control, nbp->tuple_count, nbp->at_nbp_id));
181 switch (nbp->control) {
182 case NBP_LKUP :
183 {
184 at_net_al dst_net;
185
186 dst_net = NET_VALUE(ddp->dst_net);
187 dPrintf(D_M_NBP_LOW, D_L_USR2, (" LKUP %s\n",
188 ifID != ifID_home ? "non-home" : "home"));
189 if ( ROUTING_MODE && (NET_VALUE(ddp->dst_net) != 0)
190 && ((dst_net < ifID->ifThisCableStart)
191 || (dst_net > ifID->ifThisCableEnd)) ) {
192 routing_needed(m, ifID, TRUE);
193 ddpSent = TRUE;
194 break;
195 }
196 }
197
198 if (nbp_validate_n_hash (&nbp_req, TRUE, FALSE) == 0) {
199 nbp_req.func = nbp_lkup_reply;
200 (void) nbp_search_nve(&nbp_req, ifID);
201 if (nbp_req.response) {
202 nbp_send_resp(&nbp_req);
203 }
204 }
205 #ifdef NBP_DEBUG
206 {
207 char zone[35],object[35],type[35];
208 strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
209 strlcpy(object,nbp_req.nve.object.str, sizeof(object));
210 strlcpy(type,nbp_req.nve.type.str, sizeof(type));
211 if (ifID != ifID_home)
212 dPrintf(D_M_NBP_LOW,D_L_USR2,
213 ("nbp_LKUP for:%s:%s@%s", object, type, zone));
214 }
215 #endif /* NBP_DEBUG */
216
217 break;
218 case NBP_FWDRQ:
219 {
220 register int zhome=0;
221 /* true if home zone == destination zone */
222 register int zno, i;
223 register gbuf_t *m2;
224 register int error_found =0;
225 register at_ifaddr_t *ifIDorig;
226
227 if (!ROUTING_MODE) /* for routers only! */
228 break;
229
230 ifIDorig = ifID;
231 ifID= NULL;
232 for (i = 0 ; i < RT_maxentry; i++) {
233 rt = &RT_table[i];
234 if ((rt->EntryState & RTE_STATE_PERMANENT) &&
235 NET_VALUE(ddp->dst_net) >= rt->NetStart &&
236 NET_VALUE(ddp->dst_net) <= rt->NetStop
237 ) {
238 /* sanity check */
239 if (rt->NetPort >= IF_TOTAL_MAX) {
240 dPrintf(D_M_NBP,D_L_ERROR,
241 ("nbp_input:FWDREQ: bad port# from RT_table\n"));
242 error_found = TRUE;
243 break;
244 }
245 ifID = ifID_table[rt->NetPort];
246 if (!ifID) {
247 dPrintf(D_M_NBP,D_L_ERROR,
248 ("nbp_input:FWDREQ: ifID %s\n",
249 !ifID ? "not found" : "invalid"));
250 error_found = TRUE;
251 break;
252 }
253 if (ifID->ifState == LAP_OFFLINE) {
254 dPrintf(D_M_NBP,D_L_ERROR,
255 ("nbp_input:FWDREQ: ifID offline (port %d)\n",
256 rt->NetPort));
257 error_found = TRUE;
258 break;
259 }
260 break;
261 }
262 }
263 if (error_found) /* the port is not correct */
264 break;
265
266 if (!ifID) { /* this packet is not for us, let the routing engine handle it */
267 routing_needed(m, ifIDorig, TRUE);
268 ddpSent= TRUE;
269 break;
270 }
271
272 /*
273 * At this point, we have a valid Forward request for one of our
274 * directly connected port. Convert it to a NBP Lookup
275 */
276
277 nbp->control = NBP_LKUP;
278 NET_ASSIGN(ddp->dst_net, 0);
279 ddp->dst_node = 255;
280
281
282 /*### LD 01/18/94 Check if the dest is also the home zone. */
283
284 p = nbp2zone(nbp, (u_char *)gbuf_wptr(m));
285 if ((p == NULL) || !(zno = zt_find_zname((at_nvestr_t *)p))) {
286 dPrintf(D_M_NBP,D_L_WARNING,
287 ("nbp_input: FWDRQ:zone not found\n"));
288 break;
289 }
290 if (isZoneLocal((at_nvestr_t*)p))
291 zhome = TRUE; /* one of our ports is in destination zone */
292 if (!zt_get_zmcast(ifID, (at_nvestr_t*)p, (char *)&mcastAddr)) {
293 dPrintf(D_M_NBP,D_L_ERROR,
294 ("nbp_input: FDWREQ:zt_get_zmcast error\n"));
295 break;
296 }
297
298
299 if (zhome) { /*### LD 01/18/95 In case our home is here, call back nbp */
300
301 if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
302 dPrintf(D_M_NBP,D_L_ERROR,
303 ("nbp_input: FWDRQ:gbuf_copym failed\n"));
304 break;
305 }
306
307 ddp = DATA_DDP(m2);
308 nbp = DATA_NBP(m2);
309 nbp->control = NBP_LKUP;
310 NET_ASSIGN(ddp->dst_net, 0);
311 ddp->dst_node = 255;
312 dPrintf(D_M_NBP,D_L_INFO,
313 ("nbp_input: FWDRQ:loop back for us\n"));
314 nbp_input(m2, ifID_home);
315 }
316
317 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
318 ddp_bit_reverse((unsigned char *)&mcastAddr);
319 ddp_router_output(m, ifID, ET_ADDR, 0, 0, &mcastAddr);
320 ddpSent = TRUE;
321 }
322 break;
323
324 case NBP_BRRQ:
325 {
326 register int zno; /* zone table entry numb */
327 register int ztind; /* zone bitmap index into RT_entry */
328 register int ztbit; /* zone bit to check within above index */
329 register int zhome=0; /* true if home zone == destination zone */
330 register int i;
331 register gbuf_t *m2, *m3;
332 register int fromUs = FALSE;
333 register at_socket ourSkt = 0; /* originating skt */
334
335 /* for router & MH local only */
336 if ((!(MULTIHOME_MODE && FROM_US(ddp))) && !ROUTING_MODE) {
337 dPrintf(D_M_NBP,D_L_USR2,
338 ("nbp_input: BRREQ:non router or MH local\n"));
339
340 break;
341 }
342 p = nbp2zone(nbp, (u_char *)gbuf_wptr(m));
343 if ((p == NULL) || !(zno = zt_find_zname((at_nvestr_t *)p))) {
344 break;
345 }
346 if (MULTIHOME_MODE && ifID->ifRouterState == NO_ROUTER) {
347 ((at_nvestr_t*)p)->len = 1;
348 ((at_nvestr_t*)p)->str[0] = '*';
349 }
350 if (isZoneLocal((at_nvestr_t*)p)) {
351 zhome = TRUE; /* one of our ports is in destination zone */
352 }
353 if (FROM_US(ddp)){ /* save, before we munge it */
354 fromUs = TRUE;
355 ourSkt = ddp->src_socket;
356 dPrintf(D_M_NBP,D_L_USR2,
357 ("nbp_input:BRRQ from us net:%d\n",
358 (int)NET_VALUE(ddp->src_net)));
359 }
360 /* from ZT_CLR_ZMAP */
361 i = zno - 1;
362 ztind = i >> 3;
363 ztbit = 0x80 >> (i % 8);
364 for (i=0,rt=RT_table; i<RT_maxentry; i++,rt++) {
365 if (!(rt->ZoneBitMap[ztind] & ztbit)) /* if zone not in route, skip*/
366 continue;
367 /* dPrintf(D_M_NBP, D_L_USR3,
368 ("nbp_input: BRREQ: port:%d, entry %d\n",
369 rt->NetPort, i));
370 */
371
372 ifID = ifID_table[rt->NetPort];
373 if (!ifID) {
374 dPrintf(D_M_NBP, D_L_ERROR,
375 ("nbp_input:BRRQ: ifID %s\n",
376 !ifID ? "not found" : "invalid"));
377 break;
378 }
379
380 ddp = DATA_DDP(m);
381 ddp->src_node = ifID->ifThisNode.s_node;
382 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
383 ddp->src_socket = NBP_SOCKET;
384 if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
385 dPrintf(D_M_NBP,D_L_ERROR,
386 ("nbp_input: BRREQ:gbuf_copym failed\n"));
387 break;
388 }
389
390 ddp = DATA_DDP(m2);
391 nbp = DATA_NBP(m2);
392 /* nbp->tuple[0].enu_addr.socket = NBP_SOCKET; */
393 if (MULTIHOME_MODE && fromUs ) {
394 /* set the return address of the lookup to that of the
395 interface it's going out on so that replies come back
396 on that net */
397 dPrintf(D_M_NBP,D_L_USR3,
398 ("nbp_input: BRREQ: src changed to %d.%d.%d\n",
399 ifID->ifThisNode.s_net,
400 ifID->ifThisNode.s_node, ourSkt));
401 nbp->tuple[0].enu_addr.net = htons(ifID->ifThisNode.s_net);
402 nbp->tuple[0].enu_addr.node = ifID->ifThisNode.s_node;
403 nbp->tuple[0].enu_addr.socket = ourSkt;
404 ddp->src_socket = NBP_SOCKET;
405 }
406 #if DEBUG
407 else
408 dPrintf(D_M_NBP, D_L_USR3,
409 ("nbp_input: BRREQ: not from us\n"));
410 #endif /* DEBUG */
411 dPrintf(D_M_NBP, D_L_USR3,
412 ("nbp_input dist:%d\n", rt->NetDist));
413 if (rt->NetDist == 0) { /* if direct connect, *we* do the LKUP */
414 nbp->control = NBP_LKUP;
415 NET_ASSIGN(ddp->dst_net, 0);
416 ddp->dst_node = 255;
417 if (!zt_get_zmcast(ifID, (at_nvestr_t*)p, (char *)&mcastAddr)) {
418 dPrintf(D_M_NBP,D_L_ERROR,
419 ("nbp_input: BRRQ:zt_get_zmcast error\n"));
420 break;
421 }
422 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
423 ddp_bit_reverse((unsigned char *)&mcastAddr);
424 ddp_router_output(m2, ifID, ET_ADDR, 0, 0, &mcastAddr);
425 }
426 else { /* else fwd to router */
427 ddp->dst_node = 0;
428 if (rt->NetStart == 0) /* if Ltalk */
429 NET_ASSIGN(ddp->dst_net, rt->NetStop);
430 else
431 NET_ASSIGN(ddp->dst_net, rt->NetStart);
432 nbp->control = NBP_FWDRQ;
433 ddp_router_output(m2, ifID, AT_ADDR,
434 rt->NextIRNet, rt->NextIRNode,
435 NULL);
436 }
437 }
438 if (!zhome)
439 break;
440
441 if (!(m3 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
442 dPrintf(D_M_NBP,D_L_ERROR,
443 ("nbp_input: BRREQ:gbuf_copym failed\n"));
444 break;
445 }
446
447 ddp = DATA_DDP(m3);
448 nbp = DATA_NBP(m3);
449
450 nbp->control = NBP_LKUP;
451 NET_ASSIGN(ddp->dst_net, 0);
452 ddp->dst_node = 255;
453 dPrintf(D_M_NBP,D_L_INFO, ("nbp_input: BRRQ:loop back for us\n"));
454 nbp_input(m3, ifID_home);
455 break;
456 }
457
458 case NBP_LKUP_REPLY:
459
460 if (!ROUTING_MODE) /* for routers only! */
461 break;
462
463 dPrintf(D_M_NBP,D_L_WARNING,
464 ("nbp_input: routing needed for LKUP_REPLY: from %d.%d\n",
465 NET_VALUE(ddp->src_net), ddp->src_node));
466 routing_needed(m, ifID, TRUE);
467 ddpSent = TRUE;
468 break;
469
470 default :
471 dPrintf(D_M_NBP,D_L_ERROR,
472 ("nbp_input: unhandled pkt: type:%d\n", nbp->control));
473
474 routing_needed(m, ifID, TRUE);
475 ddpSent = TRUE;
476 break;
477 } /* switch control */
478
479 if (!ddpSent)
480 gbuf_freem(m);
481 return;
482 } /* nbp_input */
483
484 static int nbp_validate_n_hash (nbp_req, wild_ok, checkLocal)
485 register nbp_req_t *nbp_req;
486 register int wild_ok;
487 register int checkLocal; /* if true check if local zone */
488 {
489 register at_nvestr_t *object, *type, *zone;
490 at_nbptuple_t *tuple;
491 register int i, part_wild;
492
493 tuple = DATA_NBP(nbp_req->request)->tuple;
494 nbp_req->flags = 0;
495 #ifdef COMMENTED_OUT
496 {
497 int net,node,skt;
498 net = ntohs(tuple->enu_addr.net);
499 node = tuple->enu_addr.node;
500 skt = tuple->enu_addr.socket;
501 dPrintf(D_M_NBP_LOW,D_L_USR4,
502 ("nbp_validate: tuple addr:%d:%d:%d\n",net,node,skt));
503 }
504 #endif /* COMMENTED_OUT */
505
506 /* tuple is in the compressed (no "filler") format */
507 object = (at_nvestr_t *)&tuple->enu_entity;
508 type = (at_nvestr_t *)(&object->str[object->len]);
509 zone = (at_nvestr_t *)(&type->str[type->len]);
510
511 if (object->len > NBP_NVE_STR_SIZE || type->len > NBP_NVE_STR_SIZE ||
512 zone->len > NBP_NVE_STR_SIZE) {
513 dPrintf(D_M_NBP_LOW, D_L_WARNING,
514 ("nbp_val_n_hash: bad str len\n"));
515 errno = EINVAL;
516 return (-1);
517 }
518
519 #ifdef NBP_DEBUG
520 {
521 char xzone[35],xobject[35],xtype[35];
522 strlcpy(xzone,zone->str, sizeof(xzone));
523 strlcpy(xobject,object->str, sizeof(xobject));
524 strlcpy(xtype,type->str, sizeof(xtype));
525 dPrintf(D_M_NBP_LOW, D_L_USR4,
526 ("nbp_validate: looking for %s:%s@%s\n",
527 xobject, xtype, xzone));
528 }
529 #endif /* NBP_DEBUG */
530 /* Is this request for our zone ?? */
531 nbp_req->nve.zone.len = zone->len;
532 nbp_req->nve.zone_hash = 0;
533 bcopy(zone->str,nbp_req->nve.zone.str, zone->len);
534
535 if (checkLocal && !isZoneLocal(zone)) {
536 char str[35];
537 strlcpy((char *)str,(char *)zone->str,sizeof(str));
538 dPrintf(D_M_NBP_LOW,D_L_WARNING,
539 ("nbp_val_n_hash bad zone: %s\n", str));
540 errno = EINVAL;
541 return(-1);
542 }
543
544 if (!DEFAULT_ZONE(zone)) {
545 nbp_req->nve.zone_hash = nbp_strhash(& nbp_req->nve.zone);
546 }
547
548 nbp_req->nve.address = tuple->enu_addr;
549 nbp_req->nve.object.len = object->len;
550 nbp_req->nve.object_hash = 0;
551 if (object->len == 1 && (object->str[0] == NBP_ORD_WILDCARD ||
552 object->str[0] == NBP_SPL_WILDCARD)) {
553 if (wild_ok)
554 nbp_req->flags |= NBP_WILD_OBJECT;
555 else {
556 dPrintf(D_M_NBP_LOW, D_L_WARNING,
557 ("nbp_val_n_hash: wild not okay\n"));
558 errno = EINVAL;
559 return (-1);
560 }
561 } else{
562 for (i = part_wild = 0; (unsigned) i<object->len; i++) {
563 if (object->str[i] == NBP_SPL_WILDCARD) {
564 if (wild_ok) {
565 if (part_wild) {
566 dPrintf(D_M_NBP_LOW, D_L_WARNING,
567 ("nbp_val_n_hash: too many parts wild\n"));
568 errno = EINVAL;
569 return (-1);
570 } else
571 part_wild++;
572 } else {
573 dPrintf(D_M_NBP_LOW, D_L_WARNING,
574 ("nbp_val_n_hash: wild not okay2\n"));
575 errno = EINVAL;
576 return (-1);
577 }
578 }
579 nbp_req->nve.object.str[i] = object->str[i];
580 }
581 if (!part_wild)
582 nbp_req->nve.object_hash =
583 nbp_strhash(&nbp_req->nve.object);
584 }
585
586 nbp_req->nve.type.len = type->len;
587 nbp_req->nve.type_hash = 0;
588 if (type->len == 1 && (type->str[0] == NBP_ORD_WILDCARD ||
589 type->str[0] == NBP_SPL_WILDCARD)) {
590 if (wild_ok)
591 nbp_req->flags |= NBP_WILD_TYPE;
592 else {
593 dPrintf(D_M_NBP_LOW, D_L_WARNING,
594 ("nbp_val_n_hash: wild not okay3\n"));
595 errno = EINVAL;
596 return (-1);
597 }
598 } else {
599 for (i = part_wild = 0; (unsigned) i<type->len; i++) {
600 if (type->str[i] == NBP_SPL_WILDCARD) {
601 if (wild_ok) {
602 if (part_wild) {
603 dPrintf(D_M_NBP_LOW, D_L_WARNING,
604 ("nbp_val_n_hash: too many parts wild2\n"));
605 errno = EINVAL;
606 return (-1);
607 } else
608 part_wild++;
609 } else {
610 errno = EINVAL;
611 return (-1);
612 }
613 }
614 nbp_req->nve.type.str[i] = type->str[i];
615 }
616 if (!part_wild)
617 nbp_req->nve.type_hash =
618 nbp_strhash(&nbp_req->nve.type);
619 }
620 #ifdef NBP_DEBUG
621 {
622 char zone[35],object[35],type[35];
623 strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
624 strlcpy(object,nbp_req.nve.object.str, sizeof(object));
625 strlcpy(type,nbp_req.nve.type.str, sizeof(type));
626 dPrintf(D_M_NBP_LOW,D_L_USR4,
627 ("nbp_validate: after hash: %s:%s@%s\n",
628 object, type, zone));
629 }
630 #endif /* NBP_DEBUG */
631 return(0);
632 } /* nbp_validate_n_hash */
633
634
635 /* Upshifts in place */
636 static void nbp_upshift (str, count)
637 register u_char *str;
638 register int count;
639 {
640 register int i, j;
641 register u_char ch;
642 static unsigned char lower_case[] =
643 {0x8a, 0x8c, 0x8d, 0x8e, 0x96, 0x9a, 0x9f, 0xbe,
644 0xbf, 0xcf, 0x9b, 0x8b, 0x88, 0};
645 static unsigned char upper_case[] =
646 {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xae,
647 0xaf, 0xce, 0xcd, 0xcc, 0xcb, 0};
648
649 for (j=0 ; j<count ; j++) {
650 ch = str[j];
651 if (ch >= 'a' && ch <= 'z')
652 str[j] = ch + 'A' - 'a';
653 else if (ch & 0x80)
654 for (i=0; lower_case[i]; i++)
655 if (ch == lower_case[i])
656 str[j] = upper_case[i];
657 }
658 }
659
660
661 u_int nbp_strhash (nvestr)
662 register at_nvestr_t *nvestr;
663 {
664 /* upshift while hashing */
665 register u_int hash = 0;
666 register int i, len;
667 union {
668 u_char h_4char[4];
669 int h_int;
670 } un;
671
672 for (i=0; (unsigned) i < nvestr->len; i+=sizeof(int)) {
673 len = MIN((size_t)(nvestr->len-i), sizeof(int));
674 if (len == sizeof(int))
675 bcopy(&(nvestr->str[i]), &un, sizeof(un));
676 else {
677 un.h_int = -1;
678 for ( ; (unsigned) i<nvestr->len; i++)
679 un.h_4char[i % sizeof(int)] = nvestr->str[i];
680 }
681 nbp_upshift (un.h_4char, len);
682 hash ^= un.h_int;
683 }
684
685 return (hash);
686 } /* nbp_strhash */
687
688 static nve_entry_t *nbp_search_nve (nbp_req, ifID)
689 register nbp_req_t *nbp_req;
690 register at_ifaddr_t *ifID; /* NULL ok */
691 {
692 register nve_entry_t *nve_entry;
693
694 #ifdef NBP_DEBUG
695 {
696 char zone[35],object[35],type[35];
697 strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
698 strlcpy(object,nbp_req.nve.object.str, sizeof(object));
699 strlcpy(type,nbp_req.nve.type.str, sizeof(type));
700 dPrintf(D_M_NBP_LOW, D_L_USR4,
701 ("nbp_search: looking for %s:%s@%s resp:0x%x\n",object,type,zone,
702 (u_int) nbp_req->response));
703 }
704 #endif /* NBP_DEBUG */
705 TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
706 if ((nbp_req->nve.zone_hash) &&
707 ((nbp_req->nve.zone_hash !=
708 nve_entry->zone_hash) &&
709 (nbp_req->nve.zone_hash != hzonehash)
710 )
711 ) {
712 dPrintf(D_M_NBP_LOW,D_L_USR4,
713 ("nbp_search: no match for zone, req hash:%x\n",
714 nbp_req->nve.zone_hash));
715 continue;
716 }
717 else { /* for this entry's zone OR no zone in request or entry */
718 /* only in singleport mode (!MULTIPORT_MODE) with
719 empty PRAM can an entry have '*' for it's zone
720 */
721 at_nvestr_t *ezone=&nve_entry->zone;
722 at_nvestr_t *rzone=&nbp_req->nve.zone;
723 if (!DEFAULT_ZONE(rzone) && !DEFAULT_ZONE(ezone)) {
724 if (nbp_strcmp (rzone, ezone, 0) != 0)
725 continue;
726 }
727 else {
728 if (MULTIHOME_MODE && ifID &&
729 (nve_entry->address.net !=
730 ifID->ifThisNode.s_net)) {
731 dPrintf(D_M_NBP, D_L_USR4,
732 ("nbp search ifID (%d) & req net (%d) not eq\n",
733 nve_entry->address.net,
734 ifID->ifThisNode.s_net));
735 continue;
736 }
737 #if DEBUG
738 if (ifID)
739 dPrintf(D_M_NBP, D_L_USR4,
740 ("nbp search ifID (%d) & req net (%d) equal\n",
741 nve_entry->address.net,
742 ifID->ifThisNode.s_net));
743 #endif /* DEBUG */
744 }
745
746 }
747 if (!(nbp_req->flags & NBP_WILD_OBJECT)) {
748 if ((nbp_req->nve.object_hash) &&
749 (nbp_req->nve.object_hash !=
750 nve_entry->object_hash))
751 continue;
752 else {
753 if (nbp_strcmp (&nbp_req->nve.object,
754 &nve_entry->object,
755 NBP_SPL_WILDCARD) != 0)
756 continue;
757 }
758 }
759
760
761 if (!(nbp_req->flags & NBP_WILD_TYPE)) {
762 if ((nbp_req->nve.type_hash) &&
763 (nbp_req->nve.type_hash !=nve_entry->type_hash))
764 continue;
765 else {
766 if (nbp_strcmp (&nbp_req->nve.type,
767 &nve_entry->type,
768 NBP_SPL_WILDCARD) != 0)
769 continue;
770 }
771 }
772
773 /* Found a match! */
774 #ifdef NBP_DEBUG
775 {
776 char zone[35],object[35],type[35];
777
778 strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
779 strlcpy(object,nbp_req.nve.object.str, sizeof(object));
780 strlcpy(type,nbp_req.nve.type.str, sizeof(type));
781 dPrintf(D_M_NBP_LOW, D_L_USR2,
782 ("nbp_search: found %s:%s@%s net:%d\n",
783 object, type, zone, (int)nve_entry->address.net));
784 }
785 #endif /* NBP_DEBUG */
786 if (nbp_req->func != NULL) {
787 if ((*(nbp_req->func))(nbp_req, nve_entry) != 0) {
788 /* errno expected to be set by func */
789 return (NULL);
790 }
791 } else
792 return (nve_entry);
793 }
794
795 errno = 0;
796 return (NULL);
797 } /* nbp_search_nve */
798
799 static int nbp_lkup_reply (nbp_req, nve_entry)
800 register nbp_req_t *nbp_req;
801 register nve_entry_t *nve_entry;
802 {
803 register at_nbptuple_t *tuple;
804 register int tuple_size, buf_len;
805 register int obj_len, type_len;
806 u_char *p;
807
808 /* size of the current tuple we want to write... */
809 tuple_size = nve_entry->object.len + 1 + /* object */
810 nve_entry->type.len + 1 + /* type */
811 2 + /* zone */
812 sizeof (at_inet_t) + 1; /* addr + enum */
813
814 buf_len = ((nbp_req->flags & NBP_WILD_MASK) ? DDP_DATA_SIZE:tuple_size);
815 if (nbp_req->response == NULL) {
816 if (nbp_setup_resp (nbp_req, buf_len) != 0)
817 /* errno expected to be set by nbp_setup_resp() */
818 return (-1);
819 }
820
821 if ((nbp_req->space_unused < tuple_size) ||
822 (DATA_NBP(nbp_req->response)->tuple_count == NBP_TUPLE_MAX)) {
823 if (nbp_send_resp (nbp_req) != 0)
824 return (-1);
825 if (nbp_setup_resp (nbp_req, buf_len) != 0)
826 return (-1);
827 }
828
829 /* At this point, we have a response buffer that can accommodate the
830 * tuple we want to write. Write it!
831 */
832 tuple = (at_nbptuple_t *)gbuf_wptr(nbp_req->response);
833 tuple->enu_addr.net = htons(nve_entry->address.net);
834 tuple->enu_addr.node = nve_entry->address.node;
835 tuple->enu_addr.socket = nve_entry->address.socket;
836 tuple->enu_enum = nve_entry->enumerator;
837
838 /* tuple is in the compressed (no "filler") format */
839 p = (u_char *)&tuple->enu_entity.object;
840 obj_len = nve_entry->object.len + 1;
841 bcopy(&nve_entry->object, p, obj_len);
842 p += obj_len;
843 type_len = nve_entry->type.len + 1;
844 bcopy(&nve_entry->type, p, type_len);
845 p += type_len;
846 p[0] = (u_char)1;
847 p[1] = '*';
848
849 nbp_req->space_unused -= tuple_size;
850 gbuf_winc(nbp_req->response, tuple_size);
851
852 /* increment the tuple count in header by 1 */
853 DATA_NBP(nbp_req->response)->tuple_count++;
854
855 return (0);
856 }
857
858
859 static int nbp_strcmp (str1, str2, embedded_wildcard)
860 register at_nvestr_t *str1, *str2;
861 register u_char embedded_wildcard; /* If str1 may contain a character
862 * that's to be treated as an
863 * embedded wildcard, this character
864 * is it. Making this special case
865 * since for zone names, squiggly
866 * equal is not to be treated as a
867 * wildcard.
868 */
869 {
870 u_char ch1,ch2;
871 register int i1, i2;
872 register int reverse = 0;
873 register int left_index;
874
875 /* Embedded wildcard, if any, could only be in the first string (str1).
876 * returns 0 if two strings are equal (modulo case), -1 otherwise
877 */
878
879 if (str1->len == 0 || str2->len == 0) {
880 return (-1);
881 }
882
883 /* Wildcards are not allowed in str2.
884 *
885 * If str1 could potentially contain an embedded wildcard, since the
886 * embedded wildcard matches ZERO OR MORE characters, str1 can not be
887 * more than 1 character longer than str2.
888 *
889 * If str1 is not supposed to have embedded wildcards, the two strs
890 * must be of equal length.
891 */
892 if ((embedded_wildcard && (str2->len < (unsigned) (str1->len-1))) ||
893 (!embedded_wildcard && (str2->len != str1->len))) {
894 return (-1);
895 }
896
897 for (i1 = i2 = left_index = 0; (unsigned) i1 < str1->len ;) {
898 ch1 = str1->str[i1];
899 ch2 = str2->str[i2];
900
901 if (embedded_wildcard && (ch1==embedded_wildcard)) {
902 /* hit the embedded wild card... start comparing from
903 * the other end of the string.
904 */
905 reverse++;
906 /* But, if embedded wildcard was the last character of
907 * the string, the two strings match, so return okay.
908 */
909 if (i1 == str1->len-1) {
910 return (0);
911 }
912
913 i1 = str1->len - 1;
914 i2 = str2->len - 1;
915
916 continue;
917 }
918
919 nbp_upshift(&ch1, 1);
920 nbp_upshift(&ch2, 1);
921
922 if (ch1 != ch2) {
923 return (-1);
924 }
925
926 if (reverse) {
927 i1--; i2--;
928 if (i1 == left_index) {
929 return (0);
930 }
931 } else {
932 i1++; i2++; left_index++;
933 }
934 }
935 return (0);
936 }
937
938
939 static void nbp_setup_hdr (nbp_req)
940 register nbp_req_t *nbp_req;
941 {
942 register at_ddp_t *ddp;
943 register at_nbp_t *nbp;
944
945 ddp = DATA_DDP(nbp_req->response);
946 nbp = DATA_NBP(nbp_req->response);
947
948 ddp->type = DDP_NBP;
949 UAS_ASSIGN(ddp->checksum, 0);
950 ddp->unused = ddp->hopcount = 0;
951
952 switch(DATA_NBP(nbp_req->request)->control) {
953 case NBP_LKUP :
954 ddp->dst_socket = nbp_req->nve.address.socket;
955 ddp->dst_node = nbp_req->nve.address.node;
956 NET_ASSIGN_NOSWAP(ddp->dst_net, nbp_req->nve.address.net);
957 nbp->control = NBP_LKUP_REPLY;
958 break;
959 }
960 nbp->at_nbp_id = DATA_NBP(nbp_req->request)->at_nbp_id;
961 return;
962 }
963
964
965 static int nbp_setup_resp (nbp_req, tuples_size)
966 register nbp_req_t *nbp_req;
967 register int tuples_size;
968 {
969 int buf_size = tuples_size + DDP_X_HDR_SIZE + NBP_HDR_SIZE;
970 nbp_req->response = gbuf_alloc(AT_WR_OFFSET+buf_size, PRI_MED);
971 if (nbp_req->response == NULL) {
972 errno = ENOBUFS;
973 return(-1);
974 }
975 gbuf_rinc(nbp_req->response, AT_WR_OFFSET);
976 gbuf_wset(nbp_req->response, DDP_X_HDR_SIZE + NBP_HDR_SIZE);
977 nbp_setup_hdr(nbp_req);
978
979 DATA_NBP(nbp_req->response)->tuple_count = 0;
980 nbp_req->space_unused = tuples_size;
981
982 return (0);
983 } /* nbp_setup_resp */
984
985
986 static int nbp_send_resp (nbp_req)
987 register nbp_req_t *nbp_req;
988 {
989 int status;
990
991 status = ddp_output(&nbp_req->response, (at_socket)NBP_SOCKET, FALSE);
992 nbp_req->response = NULL;
993 errno = status;
994 return(errno?-1:0);
995 }
996
997 void nbp_add_multicast(zone, ifID)
998 at_nvestr_t *zone;
999 at_ifaddr_t *ifID;
1000 {
1001 char data[ETHERNET_ADDR_LEN];
1002
1003 if (zone->str[0] == '*')
1004 return;
1005
1006 {
1007 char str[35];
1008 strlcpy((char *)str,(char *)zone->str,sizeof(str));
1009 dPrintf(D_M_NBP_LOW, D_L_USR3,
1010 ("nbp_add_multi getting mc for %s\n", str));
1011 }
1012 zt_get_zmcast(ifID, zone, data);
1013 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
1014 ddp_bit_reverse((unsigned char *)data);
1015 dPrintf(D_M_NBP_LOW,D_L_USR3,
1016 ("nbp_add_multi adding 0x%x%x port:%d ifID:0x%x if:%s\n",
1017 *(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
1018 /*i*/0, (u_int) ifID, ifID->ifName));
1019
1020 bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
1021 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
1022 }
1023
1024 int
1025 getNbpTableSize(void)
1026
1027 /* for SNMP, returns size in # of entries */
1028 {
1029 register nve_entry_t *nve;
1030 register int i=0;
1031
1032 for (nve = TAILQ_FIRST(&name_registry); nve; nve = TAILQ_NEXT(nve, nve_link), i++)
1033 i++;
1034 return(i);
1035 }
1036
1037 int
1038 getNbpTable(p, s, c)
1039 snmpNbpEntry_t *p;
1040 int s; /* starting entry */
1041 int c; /* # entries to copy */
1042
1043 /* for SNMP, returns section of nbp table */
1044 {
1045 register nve_entry_t *nve;
1046 register int i=0;
1047 static int nextNo=0; /* entry that *next points to */
1048 static nve_entry_t *next = (nve_entry_t*)NULL;
1049
1050 if (s && next && nextNo == s) {
1051 nve = next;
1052 i = nextNo;
1053 }
1054 else
1055 nve = TAILQ_FIRST(&name_registry);
1056
1057 for ( ; nve && c ; nve = TAILQ_NEXT(nve, nve_link), p++,i++) {
1058 if (i>= s) {
1059 p->nbpe_object = nve->object;
1060 p->nbpe_type = nve->type;
1061 c--;
1062 }
1063 }
1064 if (nve) {
1065 next = nve;
1066 nextNo = i;
1067 } else {
1068 next = (nve_entry_t*)NULL;
1069 nextNo = 0;
1070 }
1071
1072 return 0;
1073 }
1074
1075
1076 #define ZONES_PER_BLK 31 /* 31 fits within a 1k blk) */
1077 #define ZONE_BLK_SIZE ZONES_PER_BLK * sizeof(at_nvestr_t)
1078
1079 int setLocalZones(newzones, size)
1080 at_nvestr_t *newzones;
1081 int size;
1082 /* updates list of zones which are local to all active ports
1083 missing zones are not deleted, only missing zones are added.
1084 */
1085 {
1086 int bytesread=0; /* #bytes read from tuple */
1087 int i=0, dupe;
1088 gbuf_t *m;
1089 at_nvestr_t *pnve, *pnew = newzones;
1090
1091 if (!lzones) {
1092 if(!(lzones = gbuf_alloc(ZONE_BLK_SIZE, PRI_MED)))
1093 return(ENOBUFS);
1094 gbuf_wset(lzones,0);
1095 }
1096 while (bytesread < size) { /* for each new zone */
1097 {
1098 char str[35];
1099 strlcpy((char *)str,(char *)pnew->str,sizeof(str));
1100 }
1101 m = lzones;
1102 pnve = (at_nvestr_t*)gbuf_rptr(m);
1103 dupe = 0;
1104 for (i=0; i<lzonecnt && !dupe; i++,pnve++) {
1105 if (i && !(i%ZONES_PER_BLK)) {
1106 if (gbuf_cont(m)) {
1107 m = gbuf_cont(m);
1108 pnve = (at_nvestr_t*)gbuf_rptr(m);
1109 }
1110 else
1111 break;
1112 }
1113 if (pnew->len != pnve->len)
1114 continue;
1115 if (pnew->len > NBP_NVE_STR_SIZE) {
1116 return(0);
1117 }
1118 if (!strncmp((char *)pnew->str, (char *)pnve->str, pnew->len)) {
1119 dupe=1;
1120 continue;
1121 }
1122 }
1123 if (!dupe) {
1124 /* add new zone */
1125 if (lzonecnt && !(lzonecnt%ZONES_PER_BLK)) {
1126 if(!(gbuf_cont(m) = gbuf_alloc(ZONE_BLK_SIZE, PRI_MED)))
1127 return(ENOBUFS);
1128 gbuf_wset(gbuf_cont(m),0);
1129 pnve = (at_nvestr_t*)gbuf_rptr(gbuf_cont(m));
1130 }
1131 strlcpy((char *)pnve->str,(char *)pnew->str,sizeof(pnve->str));
1132 pnve->len = pnew->len;
1133 lzonecnt++;
1134 }
1135 bytesread += (pnew->len+1);
1136 pnew = (at_nvestr_t*) (((char *)pnew) + pnew->len + 1);
1137 }
1138 /* showLocalZones1(); */
1139 return(0);
1140 }
1141
1142 /**********
1143 showLocalZones1()
1144 {
1145 int i;
1146 at_nvestr_t *pnve;
1147 gbuf_t *m;
1148 char str[35];
1149
1150 for (i=0; ; i++) {
1151 if (!(pnve = getLocalZone(i))) {
1152 break;
1153 }
1154 strlcpy(str,pnve->str,sizeof(str));
1155 }
1156 }
1157
1158 *********/
1159
1160 int
1161 isZoneLocal(zone)
1162 at_nvestr_t *zone;
1163 {
1164 at_nvestr_t *pnve;
1165 int i;
1166 if (DEFAULT_ZONE(zone))
1167 return(1);
1168 for (i=0; ; i++) {
1169 if (!(pnve = getLocalZone(i)))
1170 break;
1171 if (!nbp_strcmp(pnve,zone,0))
1172 return(1);
1173 }
1174 return(0);
1175 }
1176
1177
1178 #define NULL_PNVESTR (at_nvestr_t *) 0
1179
1180 at_nvestr_t *getLocalZone(zno)
1181 int zno; /* zone number in virtual list to
1182 return, 0 for first zone */
1183 /* returns pointer to a new local zone number zno,
1184 returns null when no zones left.
1185 */
1186 {
1187 zone_usage_t ifz;
1188 ifz.zone_index = zno;
1189 if (MULTIPORT_MODE)
1190 return(getRTRLocalZone(&ifz));
1191 else
1192 return(getSPLocalZone(zno));
1193 }
1194
1195
1196 at_nvestr_t *getSPLocalZone(zno)
1197 int zno; /* zone number in virtual list to
1198 return, 0 for first zone */
1199 /* single port mode version */
1200 {
1201 int curz=0; /* current zone */
1202 gbuf_t *m;
1203 at_nvestr_t *pnve;
1204
1205 if (lzones) {
1206 m = lzones;
1207 pnve = (at_nvestr_t*)gbuf_rptr(m);
1208 }
1209 else
1210 return(NULL_PNVESTR);
1211 if ( zno>=lzonecnt )
1212 return(NULL_PNVESTR);
1213 for (curz=0; curz<zno; curz++,pnve++ ) {
1214 if ( curz<lzonecnt ) {
1215 if (curz && !(curz%ZONES_PER_BLK) ) {
1216 if (gbuf_cont(m)) {
1217 m = gbuf_cont(m);
1218 pnve = (at_nvestr_t*)gbuf_rptr(m);
1219 }
1220 else {
1221 return(NULL_PNVESTR);
1222 }
1223 }
1224 if (pnve->len > NBP_NVE_STR_SIZE) {
1225 return(NULL_PNVESTR);
1226 }
1227 }
1228 else
1229 return(NULL_PNVESTR);
1230 }
1231 return(pnve);
1232 }
1233 \f
1234 /* The following functions are used in name registration and removal */
1235
1236 int nbp_fillin_nve(entity, nve)
1237 at_entity_t *entity;
1238 nve_entry_t *nve;
1239 {
1240 register int i;
1241
1242 if (entity->object.len > NBP_NVE_STR_SIZE ||
1243 entity->type.len > NBP_NVE_STR_SIZE ||
1244 entity->zone.len > NBP_NVE_STR_SIZE) {
1245 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1246 ("nbp_fillin_nve: bad str len\n"));
1247 errno = EINVAL;
1248 return (-1);
1249 }
1250
1251 nve->zone = entity->zone;
1252 nve->zone_hash = 0;
1253 if (!isZoneLocal(&entity->zone)) {
1254 errno = EINVAL;
1255 return(-1);
1256 }
1257 /* if there's no zone, '*' gets filled in when entry is created */
1258 if (!DEFAULT_ZONE(&entity->zone))
1259 nve->zone_hash = nbp_strhash(&nve->zone);
1260
1261 nve->object = entity->object;
1262 nve->object_hash = 0;
1263 if (entity->object.len == 1 &&
1264 (entity->object.str[0] == NBP_ORD_WILDCARD ||
1265 entity->object.str[0] == NBP_SPL_WILDCARD)) {
1266 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1267 ("nbp_fillin_nve: wildcard\n"));
1268 errno = EINVAL;
1269 return (-1);
1270 }
1271 for (i = 0; i < entity->object.len; i++) {
1272 if (entity->object.str[i] == NBP_SPL_WILDCARD) {
1273 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1274 ("nbp_fillin_nve: wildcard2\n"));
1275 errno = EINVAL;
1276 return (-1);
1277 }
1278 }
1279 nve->object_hash = nbp_strhash(&nve->object);
1280
1281 nve->type = entity->type;
1282 nve->type_hash = 0;
1283 if (entity->type.len == 1 &&
1284 (entity->type.str[0] == NBP_ORD_WILDCARD ||
1285 entity->type.str[0] == NBP_SPL_WILDCARD)) {
1286 errno = EINVAL;
1287 return (-1);
1288 }
1289 for (i = 0; i < entity->type.len; i++) {
1290 if (entity->type.str[i] == NBP_SPL_WILDCARD) {
1291 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1292 ("nbp_fillin_nve: wildcard3\n"));
1293 errno = EINVAL;
1294 return (-1);
1295 }
1296 }
1297 nve->type_hash = nbp_strhash(&nve->type);
1298
1299 return(0);
1300 } /* nbp_fillin_nve */
1301
1302 nve_entry_t *nbp_find_nve(nve)
1303 nve_entry_t *nve;
1304 {
1305 register nve_entry_t *nve_entry;
1306
1307 TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
1308 if (nve->zone_hash &&
1309 ((nve->zone_hash != nve_entry->zone_hash) &&
1310 (nve->zone_hash != hzonehash))) {
1311 dPrintf(D_M_NBP_LOW,D_L_USR4,
1312 ("nbp_find_nve: no match for zone, req hash:%x\n",
1313 nve->zone_hash));
1314 continue;
1315 }
1316
1317 if ((nve->object_hash) &&
1318 (nve->object_hash != nve_entry->object_hash))
1319 continue;
1320
1321 if ((nve->type_hash) &&
1322 (nve->type_hash != nve_entry->type_hash))
1323 continue;
1324
1325 /* Found a match! */
1326 return (nve_entry);
1327 }
1328
1329 return (NULL);
1330 } /* nbp_find_nve */
1331
1332 static int nbp_enum_gen (nve_entry)
1333 register nve_entry_t *nve_entry;
1334 {
1335 register int new_enum = 0;
1336 register nve_entry_t *ne;
1337
1338 re_do:
1339 TAILQ_FOREACH(ne, &name_registry, nve_link) {
1340 if ((*(int *)&ne->address == *(int *)&nve_entry->address) &&
1341 (ne->enumerator == new_enum)) {
1342 if (new_enum == 255)
1343 return(EADDRNOTAVAIL);
1344 else {
1345 new_enum++;
1346 goto re_do;
1347 }
1348 }
1349 }
1350
1351 nve_entry->enumerator = new_enum;
1352 return (0);
1353 }
1354
1355 int nbp_new_nve_entry(nve_entry, ifID)
1356 nve_entry_t *nve_entry;
1357 at_ifaddr_t *ifID;
1358 {
1359 gbuf_t *tag;
1360 nve_entry_t *new_entry;
1361 at_nvestr_t *zone;
1362 int error;
1363
1364 if (!(valid_at_addr((at_inet_t *)&nve_entry->address))) {
1365 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1366 ("nbp_new_nve_entry: valid_at_addr\n"));
1367 return(EINVAL);
1368 }
1369 if ((error = nbp_enum_gen(nve_entry)))
1370 return(error);
1371
1372 nve_entry->unique_nbp_id = ++nbp_id_count;
1373
1374 /* Got an nve entry on hand.... allocate a buffer, copy the entry
1375 * on to it and stick it in the registry.
1376 */
1377 if ((tag = gbuf_alloc(sizeof(nve_entry_t), PRI_HI)) == NULL){
1378 return(ENOBUFS);
1379 }
1380 gbuf_wset(tag, sizeof(nve_entry_t));
1381 new_entry = (nve_entry_t *)gbuf_rptr(tag);
1382 bcopy(nve_entry, new_entry, sizeof(nve_entry_t));
1383
1384 if (DEFAULT_ZONE(&nve_entry->zone)) {
1385 /* put actual zone name in entry instead of "*" */
1386 /* if single port mode and no zone name, then a router
1387 is down, so use pram zone name hint from elap cfg */
1388 if (!MULTIPORT_MODE && ifID_home->ifZoneName.str[0] == '*') {
1389 zone = &ifID_home->startup_zone;
1390 } else {
1391 zone = &ifID_home->ifZoneName;
1392 }
1393 new_entry->zone = *zone;
1394 if ( new_entry->zone.len == 0 ) {
1395 new_entry->zone.str[0] = '*';
1396 new_entry->zone.len = 1;
1397 }
1398 new_entry->zone_hash = nbp_strhash(&new_entry->zone);
1399 }
1400 new_entry->tag = tag;
1401 new_entry->pid = proc_selfpid();
1402
1403 TAILQ_INSERT_TAIL(&name_registry, new_entry, nve_link);
1404 at_state.flags |= AT_ST_NBP_CHANGED;
1405
1406 #ifdef NBP_DEBUG
1407 {
1408 char zone[35],object[35],type[35];
1409 strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
1410 strlcpy(object,nbp_req.nve.object.str, sizeof(object));
1411 strlcpy(type,nbp_req.nve.type.str, sizeof(type));
1412 dPrintf(D_M_NBP_LOW, D_L_USR4,
1413 ("nbp_insert: adding %s:%s@%s addr:%d.%d ",
1414 object, type, zone,
1415 new_entry->address.net, new_entry->address.node));
1416 }
1417 #endif /* NBP_DEBUG */
1418
1419 nbp_add_multicast(&new_entry->zone, ifID);
1420 return (0);
1421 } /* nbp_new_nve_entry */
1422
1423 void nbp_delete_entry (nve_entry)
1424 nve_entry_t *nve_entry;
1425 {
1426 TAILQ_REMOVE(&name_registry, nve_entry, nve_link);
1427 gbuf_freem(nve_entry->tag);
1428 at_state.flags |= AT_ST_NBP_CHANGED;
1429 }
1430
1431 /* Registration of an NBP entity in multihoming mode, from AIOCNBPREG
1432 in at.c */
1433 int nbp_mh_reg(nbpP)
1434 at_nbp_reg_t *nbpP;
1435 {
1436 nve_entry_t nve;
1437 at_ifaddr_t *ifID = 0;
1438 int registered = 0;
1439 int finished = FALSE;
1440
1441 if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
1442 /* bad tuple... */
1443 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1444 ("nbp_mh_reg: bad tuple\n"));
1445 return(EINVAL);
1446 }
1447 nve.address = nbpP->addr;
1448 nve.ddptype = nbpP->ddptype;
1449
1450 if (DEFAULT_ZONE(&nbpP->name.zone)) {
1451 /* multihoming mode with the default zone specified */
1452
1453 /* now find the matching interfaces */
1454 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1455 if (nbpP->addr.net || nbpP->addr.node) {
1456 /* if address is specified */
1457 if ((nbpP->addr.net != ifID->ifThisNode.s_net ||
1458 nbpP->addr.node != ifID->ifThisNode.s_node))
1459 continue;
1460 else
1461 /* the address was specified, and
1462 we found the matching interface */
1463 finished = TRUE;
1464 } else {
1465 /* address is not specified, so fill in
1466 the address for the interface */
1467 nve.address.net = ifID->ifThisNode.s_net;
1468 nve.address.node = ifID->ifThisNode.s_node;
1469 }
1470 nve.zone = ifID->ifZoneName;
1471 nve.zone_hash = nbp_strhash(&nve.zone);
1472 if (nbp_find_nve(&nve))
1473 continue;
1474 if (nbp_new_nve_entry(&nve, ifID) == 0)
1475 registered++;
1476 }
1477 if (registered && !nbpP->addr.net && !nbpP->addr.node) {
1478 nbpP->addr.net = ifID_home->ifThisNode.s_net;
1479 nbpP->addr.node = ifID_home->ifThisNode.s_node;
1480 }
1481 } else {
1482 /* multihoming mode with a specific zone specified */
1483 /* see which segments (interfaces) are seeded for this zone */
1484 int zno;
1485 at_ifnames_t ifs_in_zone;
1486 if (!(zno = zt_find_zname(&nve.zone))) {
1487 dPrintf(D_M_NBP_LOW, D_L_WARNING,
1488 ("nbp_mh_reg: didn't find zone name\n"));
1489 return(EINVAL);
1490 }
1491 getIfUsage(zno-1, &ifs_in_zone);
1492
1493 /* now find the matching interfaces */
1494 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1495 if (!ifs_in_zone.at_if[ifID->ifPort])
1496 /* zone doesn't match */
1497 continue;
1498 else
1499 /* the zone matches, so unless the
1500 address is specified and doesn't
1501 match, we only need to do this once */
1502 finished = TRUE;
1503
1504 if (nbpP->addr.net || nbpP->addr.node) {
1505 /* address is specified */
1506 finished = FALSE;
1507 if ((nbpP->addr.net != ifID->ifThisNode.s_net ||
1508 nbpP->addr.node != ifID->ifThisNode.s_node))
1509 continue;
1510 else
1511 /* the address was specified, and
1512 we found the matching interface */
1513 finished = TRUE;
1514 } else {
1515 /* address is not specified, so fill in
1516 the address for the interface */
1517 nve.address.net = ifID->ifThisNode.s_net;
1518 nve.address.node = ifID->ifThisNode.s_node;
1519 }
1520 if (nbp_find_nve(&nve))
1521 continue;
1522 if (nbp_new_nve_entry(&nve, ifID) == 0)
1523 registered++;
1524 if (registered && !nbpP->addr.net && !nbpP->addr.node) {
1525 nbpP->addr.net = ifID->ifThisNode.s_net;
1526 nbpP->addr.node = ifID->ifThisNode.s_node;
1527 }
1528
1529 }
1530 }
1531 nbpP->unique_nbp_id = (registered > 1)? 0: nve.unique_nbp_id;
1532
1533 if (registered)
1534 return(0);
1535 else
1536 return(EADDRNOTAVAIL);
1537
1538 } /* nbp_mh_reg */