Source to bsd/netat/ddp_nbp.c
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1988, 1989, 1997, 1998 Apple Computer, Inc.
*
* The information contained herein is subject to change without
* notice and should not be construed as a commitment by Apple
* Computer, Inc. Apple Computer, Inc. assumes no responsibility
* for any errors that may appear.
*
* Confidential and Proprietary to Apple Computer, Inc.
*/
#include <sysglue.h>
/* reaching for DDP and NBP headers in the datagram */
#define DATA_DDP(mp) ((at_ddp_t *)(gbuf_rptr(mp)))
#define DATA_NBP(mp) ((at_nbp_t *)((DATA_DDP(mp))->data))
/* Get to the nve_entry_t part ofthe buffer */
#define NVE_ENTRY(mp) (nve_entry_t *)(gbuf_rptr(mp))
#include <string.h>
#include <at/appletalk.h>
#include <at/ddp.h>
#include <at/nbp.h>
#include <at/zip.h>
#include <rtmp.h>
#include <lap.h>
#include <at/elap.h> /* router */
#include <at/at_lap.h>
#include <routing_tables.h> /* router */
#include <at_elap.h> /* router */
#include <at_ddp.h> /* for FROM_US */
#include <at_snmp.h>
#ifndef MIN
#define MIN(a,b) ((a)>(b)?(b):(a))
#endif
#include "nbp.h"
#define errno nbperrno
#define NBP_DEBUG 0
/* externs */
extern at_state_t at_state, *at_statep;
extern at_if_t *ifID_table[];
/* statics */
static nve_entry_t name_registry = {&name_registry, &name_registry};
static at_nvestr_t this_zone;
static int Extended_net;
static int errno;
static gbuf_t *lzones=0; /* head of local zones list */
static int lzonecnt=0; /* # zones stored in lzones */
static u_int hzonehash=0; /* hash val of home zone */
atlock_t nve_lock;
static int nve_lock_pri;
static int nbp_lkup_reply(nbp_req_t *, nve_entry_t *);
static int nbp_strcmp(at_nvestr_t *, at_nvestr_t *, u_char);
static int nbp_setup_resp(nbp_req_t *, int);
static int nbp_send_resp(nbp_req_t *);
static int nbp_insert_entry(nve_entry_t *);
static int nbp_enum_gen(nve_entry_t *);
/* macros */
#define NBP2ENTITY(nbp) &nbp->tuple[0].en_u.en_se.entity
#define NVE_LOCK nve_lock
/* prototypes */
at_nvestr_t *getRTRLocalZone(if_zone_t *);
at_nvestr_t *getSPLocalZone(int);
at_nvestr_t *getLocalZone(int);
int nbp_add_multicast( at_nvestr_t *, at_if_t *);
int isZoneLocal(at_nvestr_t *);
u_int nbp_strhash (at_nvestr_t *);
int sethzonehash(elapp)
elap_specifics_t *elapp;
{
if (elapp->cfg.zonename.len) {
hzonehash = nbp_strhash(&elapp->cfg.zonename);
}
}
int nbp_init ()
{
void nbp_input();
at_ddp_cfg_t ddp_cfg;
/* Initialize Extended_net */
ddp_get_cfg (&ddp_cfg, 0);
if (ddp_cfg.flags & AT_IFF_LOCALTALK)
Extended_net = 0;
else
Extended_net = 1;
ATLOCKINIT(nve_lock);
return ((int)nbp_input);
}
void nbp_shutdown()
{
/* delete all NVE's and release buffers */
register nve_entry_t *nve_entry, *next_nve;
extern void nbp_delete_entry();
ATDISABLE(nve_lock_pri,NVE_LOCK);
for (nve_entry = name_registry.fwd, next_nve = nve_entry->fwd;
nve_entry != &name_registry;
nve_entry = next_nve, next_nve = nve_entry->fwd) {
nbp_delete_entry(nve_entry);
}
ATENABLE(nve_lock_pri,NVE_LOCK);
if (lzones) {
gbuf_freem(lzones);
lzones = NULL;
}
} /* nbp_shutdown */
void nbp_input (m, ifID)
register gbuf_t *m;
register at_if_t *ifID;
{
void zip_handler(), nbp_handler(), rtmp_handler();
switch (gbuf_type(m)) {
/* *** fix this later: this code may no longer be needed *** */
case MSG_ERROR :
if (*gbuf_rptr(m) == ESHUTDOWN) {
/* DDP shutting down, clean up the name registry */
nbp_shutdown();
}
break;
/* *** end code that may no longer be needed *** */
case MSG_DATA :
switch (((at_ddp_t *)(DATA_DDP(m)))->type) {
case NBP_DDP_TYPE :
nbp_handler (m, ifID);
return;
case ZIP_DDP_TYPE :
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_input: calling zip_handler\n"));
zip_handler (m);
break;
case RTMP_DDP_TYPE : /* applicable only in case of LocalTalk */
dPrintf(D_M_NBP_LOW,D_L_WARNING,
("nbp_input: calling rtmp_handler\n"));
rtmp_handler (m);
break;
}
break;
default :
dPrintf(D_M_NBP, D_L_WARNING,
("nbp_input: default_handler type=%d\n", gbuf_type(m)));
break;
}
gbuf_freem(m);
}
static
u_char *nbp2zone(nbp, maxp)
at_nbp_t *nbp;
u_char *maxp;
{
u_char *p;
p = (u_char*)NBP2ENTITY(nbp); /* p -> object */
if (p >= maxp) return NULL;
p += (*p +1); /* p -> type */
if (p >= maxp) return NULL;
p += (*p +1); /* p -> zone */
if (p >= maxp) return NULL;
if ((p + *p) >= maxp) return NULL;
return(p);
}
static void nbp_handler (m, ifID)
register gbuf_t *m;
register at_if_t *ifID;
{
register at_nbp_t *nbp = DATA_NBP(m);
register nve_entry_t *nve_entry, *next_nve;
register RT_entry *rt;
register int ddpSent = FALSE; /* true if we re-sent this pkt (don't free) */
struct etalk_addr mcastAddr;
nbp_req_t nbp_req;
nve_entry_t *nbp_search_nve();
void nbp_delete_entry();
at_ddp_t *ddp;
u_char *p;
/* Some initializations */
nbp_req.response = NULL;
nbp_req.request = m;
nbp_req.space_unused = nbp_req.flags = 0;
dPrintf(D_M_NBP_LOW, D_L_USR1,
("nbp_handler control:%d tuplecount:%d id:%d\n",
nbp->control, nbp->tuple_count, nbp->at_nbp_id));
switch (nbp->control) {
case NBP_LKUP :
{
at_net_al dst_net;
ddp = DATA_DDP(m);
dst_net = NET_VALUE(ddp->dst_net);
dPrintf(D_M_NBP_LOW, D_L_USR2, (" LKUP %s\n",
ifID != ifID_table[0] ? "non-home" : "home"));
if ( ROUTING_MODE && (NET_VALUE(ddp->dst_net) != 0)
&& ((dst_net < ifID->ifThisCableStart)
|| (dst_net > ifID->ifThisCableEnd)) ) {
routing_needed(m, ifID, TRUE);
ddpSent = TRUE;
break;
}
}
if (nbp_validate_n_hash (&nbp_req, TRUE, FALSE) == 0) {
nbp_req.func = nbp_lkup_reply;
(void) nbp_search_nve(&nbp_req, ifID);
if (nbp_req.response) {
nbp_send_resp(&nbp_req);
}
}
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strncpy(zone,nbp_req.nve.zone.str, nbp_req.nve.zone.len);
strncpy(object,nbp_req.nve.object.str, nbp_req.nve.object.len);
strncpy(type,nbp_req.nve.type.str, nbp_req.nve.type.len);
object[nbp_req.nve.object.len] = '\0';
zone[nbp_req.nve.zone.len] = '\0';
type[nbp_req.nve.type.len] = '\0';
if (ifID != ifID_table[0])
dPrintf(D_M_NBP_LOW,D_L_USR2,
("nbp_LKUP for:%s:%s@%s", object, type, zone));
}
#endif /* NBP_DEBUG */
break;
case NBP_REGISTER :
/* Whatever the outcome of this operation, we need to return
* a response to the requester; so set up the response buffers
*/
#ifdef NBP_DEBUG
{
at_net_al dst_net,src_net;
int src_node, dst_node, src_skt, dst_skt;
ddp = DATA_DDP(m);
dst_net = NET_VALUE(ddp->dst_net);
src_net = NET_VALUE(ddp->src_net);
src_node = ddp->src_node;
dst_node = ddp->dst_node;
src_skt = ddp->src_socket;
dst_skt = ddp->dst_socket;
dPrintf(D_M_NBP_LOW,D_L_USR2,
("nbp reg ddp src:%d.%d.%d ",src_net,src_node,src_skt));
dPrintf(D_M_NBP_LOW,D_L_USR2,
("dst: %d.%d.%d\n",dst_net,dst_node,dst_skt));
}
#endif /* NBP_DEBUG */
(void) nbp_setup_resp(&nbp_req, 0);
if (nbp_validate_n_hash (&nbp_req, FALSE, TRUE) != 0) {
/* bad tuple... send an error message */
goto bad;
}
nbp_req.func = NULL;
if ((nve_entry = nbp_search_nve(&nbp_req, NULL)) != NULL) {
/* We have an entry for the same name in the registry.
* This is either a duplicate request (client
* retransmission) or another request. If this is a
* retransmitted request (ie it's for the same socket),
* then return ok; else return error.
*/
if (*(int *)&nve_entry->address ==
*(int *)&nbp_req.nve.address) {
/* Send ok response */
DATA_NBP(nbp_req.response)->tuple_count = 0;
nbp_send_resp(&nbp_req);
break;
} else {
errno = EADDRNOTAVAIL;
goto bad;
}
} else {
/* Normal case; no tuple found for this name, so insert
* this tuple in the registry and return ok response.
*/
#ifdef NBP_DEBUG
{
char str[35];
char object[35];
strncpy(str,nbp_req.nve.zone.str,nbp_req.nve.zone.len);
str[nbp_req.nve.zone.len] = '\0';
strncpy(object,nbp_req.nve.object.str,nbp_req.nve.object.len);
object[nbp_req.nve.object.len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_register for zone %s (len:%d) obj:%s (len:%d)\n",
str, nbp_req.nve.zone.len, object,
nbp_req.nve.object.len));
}
#endif /* NBP_DEBUG */
if ((nbp_enum_gen(&nbp_req.nve) != 0) ||
nbp_insert_entry(&nbp_req.nve) != 0)
goto bad;
else {
/* Send okay response */
DATA_NBP(nbp_req.response)->tuple_count = 0;
nbp_send_resp(&nbp_req);
break;
}
}
bad:
DATA_NBP(nbp_req.response)->tuple_count = errno;
nbp_send_resp(&nbp_req);
break;
case NBP_DELETE :
/* Whatever the outcome of this operation, we need to return
* a response to the requester; so set up the response buffers
*/
(void) nbp_setup_resp(&nbp_req, 0);
if (nbp_validate_n_hash (&nbp_req, FALSE, TRUE) != 0) {
/* bad tuple... send an error message */
DATA_NBP(nbp_req.response)->tuple_count = errno;
nbp_send_resp(&nbp_req);
break;
}
nbp_req.func = NULL;
if (MULTIHOME_MODE &&
nbp_req.nve.zone.len == 1 &&
nbp_req.nve.zone.str[0] == '*'
) { /* if mhome & *, remove nve from all default zones */
int found = FALSE; /* if any found & deleted */
at_if_t **ifID;
for (ifID=ifID_table; *ifID; ifID++) {
nbp_req.nve.zone = (*ifID)->ifZoneName;
if ((nve_entry = nbp_search_nve(&nbp_req, NULL)) == NULL)
continue;
ATDISABLE(nve_lock_pri,NVE_LOCK);
nbp_delete_entry(nve_entry);
ATENABLE(nve_lock_pri,NVE_LOCK);
found = TRUE;
}
nbp_req.nve.zone.len = 1;
nbp_req.nve.zone.str[0] = '*';
if (found)
DATA_NBP(nbp_req.response)->tuple_count = 0;
else
DATA_NBP(nbp_req.response)->tuple_count = EADDRNOTAVAIL;
nbp_send_resp(&nbp_req);
break;
} else {
if ((nve_entry = nbp_search_nve(&nbp_req, NULL)) == NULL) {
/* Can't find the tuple we're looking for, send error*/
DATA_NBP(nbp_req.response)->tuple_count = EADDRNOTAVAIL;
nbp_send_resp(&nbp_req);
} else {
/* Normal case; tuple found for this name, so delete
* the entry from the registry and return ok response.
*/
ATDISABLE(nve_lock_pri,NVE_LOCK);
nbp_delete_entry(nve_entry);
ATENABLE(nve_lock_pri,NVE_LOCK);
DATA_NBP(nbp_req.response)->tuple_count = 0;
nbp_send_resp(&nbp_req);
}
}
break;
case NBP_CLOSE_NOTE :
ATDISABLE(nve_lock_pri,NVE_LOCK);
for (nve_entry = name_registry.fwd, next_nve = nve_entry->fwd;
nve_entry != &name_registry;
nve_entry = next_nve, next_nve = nve_entry->fwd) {
if ( DATA_DDP(m)->src_socket == nve_entry->address.socket &&
(*(int *)gbuf_wptr(m) == nve_entry->pid) &&
ot_ddp_check_socket(nve_entry->address.socket,
nve_entry->pid) < 2) {
nbp_delete_entry(nve_entry);
}
}
ATENABLE(nve_lock_pri,NVE_LOCK);
break;
case NBP_FWDRQ:
{
register int zhome=0; /* true if home zone == destination zone */
register int zno, i;
register gbuf_t *m2;
register error_found =0;
register at_if_t *ifIDorig;
if (MULTIHOME_MODE || !ROUTING_MODE) /* for routers only! */
break;
ddp = DATA_DDP(m);
ifIDorig = ifID;
ifID= NULL;
for (i = 0 ; i < RT_MAXENTRY; i++) {
rt = &RT_table[i];
if ((rt->EntryState & RTE_STATE_PERMANENT) &&
NET_VALUE(ddp->dst_net) >= rt->NetStart &&
NET_VALUE(ddp->dst_net) <= rt->NetStop
) {
/* sanity check */
if (rt->NetPort >= IF_TOTAL_MAX) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler:FWDREQ: bad port# from RT_table\n"));
error_found = TRUE;
break;
}
ifID = ifID_table[rt->NetPort];
if (!ifID || !IFID_VALID(ifID)) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler:FWDREQ: ifID %s\n",
!ifID ? "not found" : "invalid"));
error_found = TRUE;
break;
}
if (ifID->ifState == LAP_OFFLINE) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler:FWDREQ: ifID offline (port %d)\n",
rt->NetPort));
error_found = TRUE;
break;
}
break;
}
}
if (error_found) /* the port is not correct */
break;
if (!ifID) { /* this packet is not for us, let the routing engine handle it */
routing_needed(m, ifIDorig, TRUE);
ddpSent= TRUE;
break;
}
/*
* At this point, we have a valid Forward request for one of our
* direclty connected port. Convert it to a NBP Lookup
*/
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
/*### LD 01/18/94 Check if the dest is also the home zone. */
p = nbp2zone(nbp, gbuf_wptr(m));
if ((p == NULL) || !(zno = zt_find_zname(p))) {
dPrintf(D_M_NBP,D_L_WARNING,
("nbp_handler: FWDRQ:zone not found\n"));
break;
}
if (isZoneLocal((at_nvestr_t*)p))
zhome = TRUE; /* one of our ports is in destination zone */
if (!zt_get_zmcast(ifID, p, &mcastAddr)) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: FDWREQ:zt_get_zmcast error\n"));
break;
}
if (zhome) { /*### LD 01/18/95 In case our home is here, call back nbp */
if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: FWDRQ:gbuf_copym failed\n"));
break;
}
ddp = DATA_DDP(m2);
nbp = DATA_NBP(m2);
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
dPrintf(D_M_NBP,D_L_INFO,
("nbp_handler: FWDRQ:loop back for us\n"));
nbp_handler(m2, ifID_table[IFID_HOME]);
}
if ((ifID->ifType == IFTYPE_FDDITALK)
|| (ifID->ifType == IFTYPE_TOKENTALK))
ddp_bit_reverse(&mcastAddr);
ddp_router_output(m, ifID, ET_ADDR,NULL,NULL, &mcastAddr);
ddpSent = TRUE;
}
break;
case NBP_BRRQ:
{
register int zno; /* zone table entry numb */
register int ztind; /* zone bitmap index into RT_entry */
register int ztbit; /* zone bit to check within above index */
register int zhome=0; /* true if home zone == destination zone */
register int i;
register gbuf_t *m2, *m3;
register int fromUs = FALSE;
register at_socket ourSkt; /* originating skt */
ddp = DATA_DDP(m); /* for router & MH local only */
if ((MULTIHOME_MODE && !FROM_US(ddp))&& !ROUTING_MODE) {
dPrintf(D_M_NBP,D_L_USR2,
("nbp_handler: BRREQ:non router or MH local\n"));
break;
}
p = nbp2zone(nbp, gbuf_wptr(m));
if ((p == NULL) || !(zno = zt_find_zname(p))) {
break;
}
if (MULTIHOME_MODE && ifID->ifRouterState == NO_ROUTER) {
((at_nvestr_t*)p)->len = 1;
((at_nvestr_t*)p)->str[0] = '*';
}
if (isZoneLocal((at_nvestr_t*)p)) {
zhome = TRUE; /* one of our ports is in destination zone */
}
if (FROM_US(ddp)){ /* save, before we munge it */
fromUs = TRUE;
ourSkt = ddp->src_socket;
dPrintf(D_M_NBP,D_L_USR2,
("nbp_handler:BRRQ from us net:%d\n",
(int)NET_VALUE(ddp->src_net)));
}
/* from ZT_CLR_ZMAP */
i = zno - 1;
ztind = i >> 3;
ztbit = 0x80 >> (i % 8);
for (i=0,rt=RT_table; i<RT_MAXENTRY; i++,rt++) {
if (!(rt->ZoneBitMap[ztind] & ztbit)) /* if zone not in route, skip*/
continue;
/* dPrintf(D_M_NBP, D_L_USR3,
("nbp_handler: BRREQ: port:%d, entry %d\n",
rt->NetPort, i));
*/
ifID = ifID_table[rt->NetPort];
if (!ifID || !IFID_VALID(ifID)) {
dPrintf(D_M_NBP, D_L_ERROR,
("nbp_handler:BRRQ: ifID %s\n",
!ifID ? "not found" : "invalid"));
break;
}
ddp = DATA_DDP(m);
ddp->src_node = ifID->ifThisNode.atalk_node;
NET_NET(ddp->src_net, ifID->ifThisNode.atalk_net);
ddp->src_socket = NBP_SOCKET;
if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: BRREQ:gbuf_copym failed\n"));
break;
}
ddp = DATA_DDP(m2);
nbp = DATA_NBP(m2);
/* nbp->tuple[0].enu_addr.socket = NBP_SOCKET; */
if (MULTIHOME_MODE && fromUs ) {
/* set the return address of the lookup to that of the
interface it's going out on so that replies come back
on that net */
dPrintf(D_M_NBP,D_L_USR3,
("nbp_handler: BRREQ: src changed to %d.%d.%d\n",
NET_VALUE(ifID->ifThisNode.atalk_net),
ifID->ifThisNode.atalk_node, ourSkt));
NET_NET(nbp->tuple[0].enu_addr.net,ifID->ifThisNode.atalk_net);
nbp->tuple[0].enu_addr.node = ifID->ifThisNode.atalk_node;
nbp->tuple[0].enu_addr.socket = ourSkt;
ddp->src_socket = NBP_SOCKET;
}
else
dPrintf(D_M_NBP, D_L_USR3,
("nbp_handler: BRREQ: not from us\n"));
dPrintf(D_M_NBP, D_L_USR3,
("nbp_handler dist:%d\n", rt->NetDist));
if (rt->NetDist == 0) { /* if direct connect, *we* do the LKUP */
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
if (!zt_get_zmcast(ifID, p, &mcastAddr)) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: BRRQ:zt_get_zmcast error\n"));
break;
}
if ((ifID->ifType == IFTYPE_FDDITALK)
|| (ifID->ifType == IFTYPE_TOKENTALK))
ddp_bit_reverse(&mcastAddr);
ddp_router_output(m2, ifID, ET_ADDR, NULL, NULL, &mcastAddr);
}
else { /* else fwd to router */
ddp->dst_node = 0;
if (rt->NetStart == 0) /* if Ltalk */
NET_ASSIGN(ddp->dst_net, rt->NetStop);
else
NET_ASSIGN(ddp->dst_net, rt->NetStart);
nbp->control = NBP_FWDRQ;
ddp_router_output(m2, ifID, AT_ADDR, rt->NextIRNet, rt->NextIRNode, NULL);
}
}
if (!zhome)
break;
if (!(m3 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: BRREQ:gbuf_copym failed\n"));
break;
}
ddp = DATA_DDP(m3);
nbp = DATA_NBP(m3);
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
dPrintf(D_M_NBP,D_L_INFO,
("nbp_handler: BRRQ:loop back for us\n"));
nbp_handler(m3, ifID_table[IFID_HOME]);
break;
}
case NBP_LKUP_REPLY:
if (MULTIHOME_MODE || !ROUTING_MODE) /* for routers only! */
break;
ddp = DATA_DDP(m);
dPrintf(D_M_NBP,D_L_WARNING,
("nbp_handler: routing needed for LKUP_REPLY: from %d.%d\n",
NET_VALUE(ddp->src_net), ddp->src_node));
routing_needed(m, ifID, TRUE);
ddpSent = TRUE;
break;
default :
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_handler: unhandled pkt: type:%d\n", nbp->control));
routing_needed(m, ifID, TRUE);
ddpSent = TRUE;
break;
} /* switch control */
if (!ddpSent)
gbuf_freem(m);
return;
}
static void zip_handler (m)
gbuf_t *m;
{
at_ddp_t *ddp = DATA_DDP(m);
register at_zip_t *zip = ZIP_ZIP(ddp);
register char old_zone_len;
register char new_zone_len;
register char mcast_len;
char *new_zone;
switch (zip->command) {
case ZIP_NOTIFY :
/* ZipNotify packet forwarded by ZIP module...
* change the zone name this_zone.
*/
old_zone_len = zip->data[4];
mcast_len = zip->data[4+old_zone_len+1];
new_zone_len = zip->data[4+old_zone_len+1+mcast_len+1];
new_zone = &zip->data[4+old_zone_len+1+mcast_len+1];
bcopy(new_zone, &this_zone, new_zone_len + 1);
break;
default :
/* ignore all the packets we don't know about */
break;
} /* switch command */
return;
}
static void rtmp_handler (m)
gbuf_t *m;
{
at_ddp_t *ddp = DATA_DDP(m);
at_rtmp *rtmp = (at_rtmp *)ddp->data;
at_net new_net;
register nve_entry_t *nve_entry;
NET_NET(new_net, rtmp->at_rtmp_this_net);
for (nve_entry = name_registry.fwd; nve_entry != &name_registry ;
nve_entry = nve_entry->fwd)
NET_NET(nve_entry->address.net, new_net);
}
static int nbp_validate_n_hash (nbp_req, wild_ok, checkLocal)
register nbp_req_t *nbp_req;
register int wild_ok;
register int checkLocal; /* if true check if local zone */
{
register at_nvestr_t *object, *type, *zone;
at_nbptuple_t *tuple;
register int i, part_wild;
u_int nbp_strhash();
tuple = DATA_NBP(nbp_req->request)->tuple;
nbp_req->flags = 0;
#ifdef COMMENTED_OUT
{
int net,node,skt;
net = NET_VALUE(tuple->enu_addr.net);
node = tuple->enu_addr.node;
skt = tuple->enu_addr.socket;
dPrintf(D_M_NBP_LOW,D_L_USR4,
("nbp_validate: tuple addr:%d:%d:%d\n",net,node,skt));
}
#endif /* COMMENTED_OUT */
object = (at_nvestr_t *)tuple->enu_name;
type = (at_nvestr_t *)(&object->str[object->len]);
zone = (at_nvestr_t *)(&type->str[type->len]);
if (object->len > NBP_NVE_STR_SIZE || type->len > NBP_NVE_STR_SIZE ||
zone->len > NBP_NVE_STR_SIZE) {
errno = EINVAL;
return (-1);
}
#ifdef NBP_DEBUG
{
char xzone[35],xobject[35],xtype[35];
strncpy(xzone,zone->str, zone->len);
strncpy(xobject,object->str, object->len);
strncpy(xtype,type->str, type->len);
xobject[object->len] = '\0';
xzone[zone->len] = '\0';
xtype[type->len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_validate: looking for %s:%s@%s\n",
xobject, xtype, xzone));
}
#endif /* NBP_DEBUG */
/* Is this request for our zone ?? */
nbp_req->nve.zone.len = zone->len;
nbp_req->nve.zone_hash = 0;
bcopy(zone->str,nbp_req->nve.zone.str, zone->len);
if (checkLocal && !isZoneLocal(zone)) {
char str[35];
strncpy(str,zone->str,zone->len);
str[zone->len] = '\0';
dPrintf(D_M_NBP_LOW,D_L_WARNING,
("nbp_val_n_hash bad zone: %s\n", str));
errno = EINVAL;
return(-1);
}
if (Extended_net) {
/* EtherTalk...
* The zone name in the request must match either "*" or
* our zone name (this_zone). Zero length zone field is the
* same as "*".
*/
if (zone->len != 0) {
if (!(zone->len == 1 && zone->str[0] == '*')) {
nbp_req->nve.zone_hash =
nbp_strhash(& nbp_req->nve.zone);
}
#ifdef COMMENTED_OUT
/* we allow multi-zone registration now, so
the actual zone name will be checked in
nbp_search_nve() */
if (nbp_strcmp(zone, &this_zone, NULL) != 0) {
errno = EINVAL;
return (-1);
}
#endif /* COMMENTED_OUT */
}
} else {
/* LocalTalk...
* "this_zone" variable will not have been initialized, since
* there's no interaction between NBP and ZIP for LocalTalk.
* We are assuming that the zone name field in a lookup
* request packet will always contain a legal value.
* One check that could be performed here (but is not) is :
* make sure that if there's no router around on the
* net, the zone name in the lookup request must be "*". If
* it's anything else, reject the packet.
*/
}
nbp_req->nve.address = tuple->enu_addr;
nbp_req->nve.object.len = object->len;
nbp_req->nve.object_hash = 0;
if (object->len == 1 && (object->str[0] == NBP_ORD_WILDCARD ||
object->str[0] == NBP_SPL_WILDCARD)) {
if (wild_ok)
nbp_req->flags |= NBP_WILD_OBJECT;
else {
errno = EINVAL;
return (-1);
}
} else{
for (i = part_wild = 0; (unsigned) i<object->len; i++) {
if (object->str[i] == NBP_SPL_WILDCARD)
if (wild_ok)
if (part_wild) {
errno = EINVAL;
return (-1);
} else
part_wild++;
else {
errno = EINVAL;
return (-1);
}
nbp_req->nve.object.str[i] = object->str[i];
}
if (!part_wild)
nbp_req->nve.object_hash =
nbp_strhash(&nbp_req->nve.object);
}
nbp_req->nve.type.len = type->len;
nbp_req->nve.type_hash = 0;
if (type->len == 1 && (type->str[0] == NBP_ORD_WILDCARD ||
type->str[0] == NBP_SPL_WILDCARD)) {
if (wild_ok)
nbp_req->flags |= NBP_WILD_TYPE;
else {
errno = EINVAL;
return (-1);
}
} else {
for (i = part_wild = 0; (unsigned) i<type->len; i++) {
if (type->str[i] == NBP_SPL_WILDCARD)
if (wild_ok)
if (part_wild) {
errno = EINVAL;
return (-1);
} else
part_wild++;
else {
errno = EINVAL;
return (-1);
}
nbp_req->nve.type.str[i] = type->str[i];
}
if (!part_wild)
nbp_req->nve.type_hash =
nbp_strhash(&nbp_req->nve.type);
}
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strncpy(zone,nbp_req->nve.zone.str, nbp_req->nve.zone.len);
strncpy(object,nbp_req->nve.object.str, nbp_req->nve.object.len);
strncpy(type,nbp_req->nve.type.str, nbp_req->nve.type.len);
object[nbp_req->nve.object.len] = '\0';
zone[nbp_req->nve.zone.len] = '\0';
type[nbp_req->nve.type.len] = '\0';
dPrintf(D_M_NBP_LOW,D_L_USR4,
("nbp_validate: after hash: %s:%s@%s\n",
object, type, zone));
}
#endif /* NBP_DEBUG */
return(0);
}
/* Upshifts in place */
static void nbp_upshift (str, count)
register u_char *str;
register int count;
{
register int i, j;
register u_char ch;
static unsigned char lower_case[] =
{0x8a, 0x8c, 0x8d, 0x8e, 0x96, 0x9a, 0x9f, 0xbe,
0xbf, 0xcf, 0x9b, 0x8b, 0x88, 0};
static unsigned char upper_case[] =
{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xae,
0xaf, 0xce, 0xcd, 0xcc, 0xcb, 0};
for (j=0 ; j<count ; j++) {
ch = str[j];
if (ch >= 'a' && ch <= 'z')
str[j] = ch + 'A' - 'a';
else if (ch & 0x80)
for (i=0; lower_case[i]; i++)
if (ch == lower_case[i])
str[j] = upper_case[i];
}
}
static u_int nbp_strhash (nvestr)
register at_nvestr_t *nvestr;
{
/* upshift while hashing */
register u_int hash = 0;
register int i, len;
union {
u_char h_4char[4];
int h_int;
} un;
for (i=0; (unsigned) i < nvestr->len; i+=sizeof(int)) {
len = MIN((nvestr->len-i), sizeof(int));
if (len == sizeof(int))
bcopy(&(nvestr->str[i]), &un, sizeof(un));
else {
un.h_int = -1;
for ( ; (unsigned) i<nvestr->len; i++)
un.h_4char[i % sizeof(int)] = nvestr->str[i];
}
nbp_upshift (un.h_4char, len);
hash ^= un.h_int;
}
return (hash);
}
static nve_entry_t *nbp_search_nve (nbp_req, ifID)
register nbp_req_t *nbp_req;
register at_if_t *ifID; /* NULL ok */
{
register nve_entry_t *nve_entry;
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strncpy(zone,nbp_req->nve.zone.str, nbp_req->nve.zone.len);
strncpy(object,nbp_req->nve.object.str, nbp_req->nve.object.len);
strncpy(type,nbp_req->nve.type.str, nbp_req->nve.type.len);
object[nbp_req->nve.object.len] = '\0';
zone[nbp_req->nve.zone.len] = '\0';
type[nbp_req->nve.type.len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_search: looking for %s:%s@%s resp:0x%x\n",object,type,zone,
(u_int) nbp_req->response));
}
#endif /* NBP_DEBUG */
ATDISABLE(nve_lock_pri,NVE_LOCK);
for (nve_entry = name_registry.fwd; nve_entry != &name_registry ;
nve_entry = nve_entry->fwd) {
if ((nbp_req->nve.zone_hash) &&
((nbp_req->nve.zone_hash !=
nve_entry->zone_hash) &&
(nbp_req->nve.zone_hash != hzonehash)
)
) {
dPrintf(D_M_NBP_LOW,D_L_USR4,
("nbp_search: no match for zone, req hash:%x\n",
nbp_req->nve.zone_hash));
continue;
}
else { /* for this entry's zone OR no zone in request or entry */
/* only in singleport mode (!MULTIPORT_MODE) with empty PRAM
can an entry have '*' for it's zone
*/
at_nvestr_t *ezone=&nve_entry->zone;
at_nvestr_t *rzone=&nbp_req->nve.zone;
/* if (!(rzone->len == 1 && rzone->str[0] == '*')) { */
if (!DEFAULT_ZONE(rzone) && !DEFAULT_ZONE(ezone)) {
if (nbp_strcmp (rzone, ezone, 0) != 0)
continue;
}
else {
if (MULTIHOME_MODE && ifID &&
NET_NOTEQ(nve_entry->address.net, ifID->ifThisNode.atalk_net)) {
dPrintf(D_M_NBP, D_L_USR4,
("nbp search ifID (%d) & req net (%d) not eq\n",
NET_VALUE(nve_entry->address.net),
NET_VALUE(ifID->ifThisNode.atalk_net)));
continue;
}
dPrintf(D_M_NBP, D_L_USR4,
("nbp search ifID (%d) & req net (%d) equal\n",
NET_VALUE(nve_entry->address.net),
NET_VALUE(ifID->ifThisNode.atalk_net)));
}
}
if (!(nbp_req->flags & NBP_WILD_OBJECT)) {
if ((nbp_req->nve.object_hash) &&
(nbp_req->nve.object_hash !=
nve_entry->object_hash))
continue;
else {
if (nbp_strcmp (&nbp_req->nve.object,
&nve_entry->object,
NBP_SPL_WILDCARD) != 0)
continue;
}
}
if (!(nbp_req->flags & NBP_WILD_TYPE)) {
if ((nbp_req->nve.type_hash) &&
(nbp_req->nve.type_hash !=nve_entry->type_hash))
continue;
else {
if (nbp_strcmp (&nbp_req->nve.type,
&nve_entry->type,
NBP_SPL_WILDCARD) != 0)
continue;
}
}
/* Found a match! */
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
int net;
net = NET_VALUE(nve_entry->address.net);
strncpy(zone,nbp_req->nve.zone.str, nbp_req->nve.zone.len);
strncpy(object,nbp_req->nve.object.str, nbp_req->nve.object.len);
strncpy(type,nbp_req->nve.type.str, nbp_req->nve.type.len);
object[nbp_req->nve.object.len] = '\0';
zone[nbp_req->nve.zone.len] = '\0';
type[nbp_req->nve.type.len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR2,
("nbp_search: found %s:%s@%s net:%d\n",
object, type, zone, net));
}
#endif /* NBP_DEBUG */
if (nbp_req->func != NULL) {
if ((*(nbp_req->func))(nbp_req, nve_entry) != 0) {
/* errno expected to be set by func */
ATENABLE(nve_lock_pri,NVE_LOCK);
return (NULL);
}
} else {
ATENABLE(nve_lock_pri,NVE_LOCK);
return (nve_entry);
}
}
ATENABLE(nve_lock_pri,NVE_LOCK);
errno = 0;
return (NULL);
}
static int nbp_lkup_reply (nbp_req, nve_entry)
register nbp_req_t *nbp_req;
register nve_entry_t *nve_entry;
{
register at_nbptuple_t *tuple;
register int tuple_size, buf_len;
register int obj_len, type_len;
/* size of the current tuple we want to write... */
tuple_size = nve_entry->object.len + 1 + /* object */
nve_entry->type.len + 1 + /* type */
2 + /* zone */
sizeof (at_inet_t) + 1; /* addr + enum */
buf_len = ((nbp_req->flags & NBP_WILD_MASK) ? DDP_DATA_SIZE:tuple_size);
if (nbp_req->response == NULL) {
if (nbp_setup_resp (nbp_req, buf_len) != 0)
/* errno expected to be set by nbp_setup_resp() */
return (-1);
}
if ((nbp_req->space_unused < tuple_size) ||
(DATA_NBP(nbp_req->response)->tuple_count == NBP_TUPLE_MAX)) {
if (nbp_send_resp (nbp_req) != 0)
return (-1);
if (nbp_setup_resp (nbp_req, buf_len) != 0)
return (-1);
}
/* At this point, we have a response buffer that can accommodate the
* tuple we want to write. Write it!
*/
tuple = (at_nbptuple_t *)gbuf_wptr(nbp_req->response);
tuple->enu_addr = nve_entry->address;
tuple->enu_enum = nve_entry->enumerator;
obj_len = nve_entry->object.len + 1;
bcopy(&nve_entry->object, &tuple->enu_name[0], obj_len);
type_len = nve_entry->type.len + 1;
bcopy(&nve_entry->type, &tuple->enu_name[obj_len], type_len);
tuple->enu_name[obj_len + type_len] = 1;
tuple->enu_name[obj_len + type_len + 1] = '*';
nbp_req->space_unused -= tuple_size;
gbuf_winc(nbp_req->response, tuple_size);
/* increment the tuple count in header by 1 */
DATA_NBP(nbp_req->response)->tuple_count++;
return (0);
}
static int nbp_strcmp (str1, str2, embedded_wildcard)
register at_nvestr_t *str1, *str2;
register u_char embedded_wildcard; /* If str1 may contain a character
* that's to be treated as an
* embedded wildcard, this character
* is it. Making this special case
* since for zone names, squiggly
* equal is not to be treated as a
* wildcard.
*/
{
u_char ch1,ch2;
register int i1, i2;
register int reverse = 0;
register int left_index;
/* Embedded wildcard, if any, could only be in the first string (str1).
* returns 0 if two strings are equal (modulo case), -1 otherwise
*/
if (str1->len == 0 || str2->len == 0) {
return (-1);
}
/* Wildcards are not allowed in str2.
*
* If str1 could potentially contain an embedded wildcard, since the
* embedded wildcard matches ZERO OR MORE characters, str1 can not be
* more than 1 character longer than str2.
*
* If str1 is not supposed to have embedded wildcards, the two strs
* must be of equal length.
*/
if ((embedded_wildcard && (str2->len < (unsigned) (str1->len-1))) ||
(!embedded_wildcard && (str2->len != str1->len))) {
return (-1);
}
for (i1 = i2 = left_index = 0; (unsigned) i1 < str1->len ;) {
ch1 = str1->str[i1];
ch2 = str2->str[i2];
if (embedded_wildcard && (ch1==embedded_wildcard)) {
/* hit the embedded wild card... start comparing from
* the other end of the string.
*/
reverse++;
/* But, if embedded wildcard was the last character of
* the string, the two strings match, so return okay.
*/
if (i1 == str1->len-1) {
return (0);
}
i1 = str1->len - 1;
i2 = str2->len - 1;
continue;
}
nbp_upshift(&ch1, 1);
nbp_upshift(&ch2, 1);
if (ch1 != ch2) {
return (-1);
}
if (reverse) {
i1--; i2--;
if (i1 == left_index) {
return (0);
}
} else {
i1++; i2++; left_index++;
}
}
return (0);
}
static void nbp_setup_hdr (nbp_req)
register nbp_req_t *nbp_req;
{
register at_ddp_t *ddp;
register at_nbp_t *nbp;
ddp = DATA_DDP(nbp_req->response);
nbp = DATA_NBP(nbp_req->response);
ddp->type = NBP_DDP_TYPE;
UAS_ASSIGN(ddp->checksum, 0);
ddp->unused = ddp->hopcount = 0;
switch(DATA_NBP(nbp_req->request)->control) {
case NBP_LKUP :
ddp->dst_socket = nbp_req->nve.address.socket;
ddp->dst_node = nbp_req->nve.address.node;
NET_NET(ddp->dst_net, nbp_req->nve.address.net);
nbp->control = NBP_LKUP_REPLY;
break;
case NBP_REGISTER :
case NBP_DELETE :
ddp->dst_socket = DATA_DDP(nbp_req->request)->src_socket;
ddp->dst_node = DATA_DDP(nbp_req->request)->src_node;
NET_NET(ddp->dst_net, DATA_DDP(nbp_req->request)->src_net);
nbp->control = NBP_STATUS_REPLY;
break;
}
nbp->at_nbp_id = DATA_NBP(nbp_req->request)->at_nbp_id;
return;
}
static int nbp_setup_resp (nbp_req, tuples_size)
register nbp_req_t *nbp_req;
register int tuples_size;
{
int buf_size = tuples_size + DDP_X_HDR_SIZE + NBP_HDR_SIZE;
nbp_req->response = gbuf_alloc(AT_WR_OFFSET+buf_size, PRI_MED);
if (nbp_req->response == NULL) {
errno = ENOBUFS;
return(-1);
}
gbuf_rinc(nbp_req->response, AT_WR_OFFSET);
gbuf_wset(nbp_req->response, DDP_X_HDR_SIZE + NBP_HDR_SIZE);
nbp_setup_hdr(nbp_req);
DATA_NBP(nbp_req->response)->tuple_count = 0;
nbp_req->space_unused = tuples_size;
return (0);
} /* nbp_setup_resp */
static int nbp_send_resp (nbp_req)
register nbp_req_t *nbp_req;
{
int status;
status = ddp_output(&nbp_req->response, (at_socket)NBP_SOCKET, NULL);
if (status)
gbuf_freem(nbp_req->response);
nbp_req->response = NULL;
errno = status;
return(errno?-1:0);
}
static int nbp_insert_entry (nve_entry)
nve_entry_t *nve_entry;
{
gbuf_t *tag;
nve_entry_t *new_entry;
int i;
at_if_t *ifID;
at_nvestr_t *zone;
int multiZone = 0; /* true if we should do multiple registrations */
int defaultZone = 0; /* true if zone is '*' */
/* Got an nve entry on hand.... allocate a buffer, copy the entry
* on to it and stick it in the registry.
*/
if (nve_entry->zone.str[0] == '*')
defaultZone=TRUE;
if (defaultZone && MULTIHOME_MODE) {
multiZone = TRUE;
}
for (ifID = ifID_table[0],i=0; ifID; ifID=ifID_table[++i]) {
if (!defaultZone && MULTIPORT_MODE ) {
/* if registering for a specific zone and we have multiple
I/F's running, find the first I/F containing the
requested zone
*/
int zno;
char ifs_in_zone[IF_TOTAL_MAX];
if (!(zno = zt_find_zname(&nve_entry->zone))) {
errno = ENOENT;
return(-1);
}
getIfUsage(zno-1, ifs_in_zone);
for(; ifID; ifID=ifID_table[++i])
if (ifs_in_zone[i])
break;
if (!ifID) {
errno = ENOENT;
return(-1);
}
}
if ((tag = gbuf_alloc(sizeof(nve_entry_t), PRI_HI)) == NULL){
errno = ENOBUFS;
return (-1);
}
gbuf_wset(tag, sizeof(nve_entry_t));
new_entry = (nve_entry_t *)gbuf_rptr(tag);
bcopy(nve_entry, new_entry, sizeof(nve_entry_t));
NET_NET(new_entry->address.net, ifID->ifThisNode.atalk_net);
new_entry->address.node = ifID->ifThisNode.atalk_node;
if (multiZone ){
new_entry->zone = ZT_table[ifID->ifDefZone-1].Zone;
new_entry->zone_hash = nbp_strhash(&new_entry->zone);
}
if (defaultZone && !multiZone ) {
/* put actual zone name in entry instead of "*" */
/* if single port mode and no zone name, then a router
is down, so use pram zone name hint from elap cfg */
if (!MULTIPORT_MODE && ifID->ifZoneName.str[0] == '*') {
elap_specifics_t *elapp;
elapp = (elap_specifics_t*)(ifID_table[IFID_HOME]->ifLapp);
zone = &elapp->cfg.zonename;
}
else {
zone = &ifID_table[IFID_HOME]->ifZoneName;
}
new_entry->zone = *zone;
if ( new_entry->zone.len == 0 ) {
new_entry->zone.str[0] = '*';
new_entry->zone.len = 1;
}
new_entry->zone_hash = nbp_strhash(&new_entry->zone);
}
new_entry->tag = tag;
#ifdef NEXT
/* Fixes PR 2243737: didn't deregister nbp entity properly */
new_entry->pid = current_proc()->p_pid;
#else
new_entry->pid = getpid();
#endif
ATDISABLE(nve_lock_pri,NVE_LOCK);
ddp_insque(new_entry, name_registry.fwd);
ATENABLE(nve_lock_pri,NVE_LOCK);
at_statep->flags |= AT_ST_NBP_CHANGED;
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strncpy(zone,new_entry->zone.str, new_entry->zone.len);
strncpy(object,new_entry->object.str, new_entry->object.len);
strncpy(type,new_entry->type.str, new_entry->type.len);
object[new_entry->object.len] = '\0';
zone[new_entry->zone.len] = '\0';
type[new_entry->type.len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_insert:adding %s:%s@%s i/f:%s ",
object, type, zone, ifID->ifName));
dPrintf(D_M_NBP_LOW, D_L_USR4,
("addr:%d.%d\n",
NET_VALUE(new_entry->address.net),
new_entry->address.node));
}
#endif /* NBP_DEBUG */
nbp_add_multicast(&new_entry->zone, ifID);
if (!multiZone)
break;
}
return (0);
}
nbp_add_multicast(zone, ifID)
at_nvestr_t *zone;
at_if_t *ifID;
{
char data[ETHERNET_ADDR_LEN];
int i;
if (zone->str[0] == '*')
return;
{
char str[35];
strncpy(str,zone->str,zone->len);
str[zone->len] = '\0';
dPrintf(D_M_NBP_LOW, D_L_USR3,
("nbp_add_multi getting mc for %s\n", str));
}
zt_get_zmcast(ifID, zone, data);
if ((ifID->ifType == IFTYPE_FDDITALK)
|| (ifID->ifType == IFTYPE_TOKENTALK))
ddp_bit_reverse(data);
dPrintf(D_M_NBP_LOW,D_L_USR3,
("nbp_add_multi adding 0x%x%x port:%d ifID:0x%x if:%s\n",
*(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
i, (u_int) ifID, ifID->ifName));
elap_control(ifID, ELAP_REG_ZONE_MCAST, data);
}
static void nbp_delete_entry (nve_entry)
nve_entry_t *nve_entry;
{
ddp_remque(nve_entry);
gbuf_freem(nve_entry->tag);
at_statep->flags |= AT_ST_NBP_CHANGED;
}
static int nbp_enum_gen (nve_entry)
register nve_entry_t *nve_entry;
{
register int new_enum = 0;
register nve_entry_t *ne;
ATDISABLE(nve_lock_pri,NVE_LOCK);
re_do:
for (ne = name_registry.fwd; ne != &name_registry; ne = ne->fwd) {
if ((*(int *)&ne->address == *(int *)&nve_entry->address) &&
(ne->enumerator == new_enum)) {
if (new_enum == 255) {
errno = EADDRNOTAVAIL;
ATENABLE(nve_lock_pri,NVE_LOCK);
return (-1);
} else {
new_enum++;
goto re_do;
}
}
}
ATENABLE(nve_lock_pri,NVE_LOCK);
nve_entry->enumerator = new_enum;
return (0);
}
getNbpTableSize()
/* for SNMP, returns size in # of entries */
{
register nve_entry_t *nve;
register int i=0;
ATDISABLE(nve_lock_pri,NVE_LOCK);
for (nve = name_registry.fwd; nve != &name_registry; nve = nve->fwd, i++)
;
ATENABLE(nve_lock_pri,NVE_LOCK);
return(i);
}
getNbpTable(p,s,c)
snmpNbpEntry_t *p;
int s; /* starting entry */
int c; /* # entries to copy */
/* for SNMP, returns section of nbp table */
{
register nve_entry_t *nve;
register int i=0;
static int nextNo=0; /* entry that *next points to */
static nve_entry_t *next = (nve_entry_t*)NULL;
if (s && next && nextNo == s) {
nve = next;
i = nextNo;
}
else
nve = name_registry.fwd;
ATDISABLE(nve_lock_pri,NVE_LOCK);
for ( ; nve != &name_registry && c ; nve = nve->fwd, p++,i++) {
if (i>= s) {
p->nbpe_object = nve->object;
p->nbpe_type = nve->type;
c--;
}
}
ATENABLE(nve_lock_pri,NVE_LOCK);
if (nve != &name_registry) {
next = nve;
nextNo = i;
}else {
next = (nve_entry_t*)NULL;
nextNo = 0;
}
}
#define ZONES_PER_BLK 31 /* 31 fits within a 1k blk) */
#define ZONE_BLK_SIZE ZONES_PER_BLK * sizeof(at_nvestr_t)
setLocalZones(newzones, size)
at_nvestr_t *newzones;
int size;
/* updates list of zones which are local to all active ports
missing zones are not deleted, only missing zones are added.
*/
{
int bytesread=0; /* #bytes read from tuple */
int i=0, dupe;
gbuf_t *m;
at_nvestr_t *pnve, *pnew = newzones;
if (!lzones) {
if(!(lzones = gbuf_alloc(ZONE_BLK_SIZE, PRI_MED)))
return(ENOBUFS);
gbuf_wset(lzones,0);
}
while (bytesread < size) { /* for each new zone */
{
char str[35];
strncpy(str,pnew->str,pnew->len);
str[pnew->len] = '\0';
}
m = lzones;
pnve = (at_nvestr_t*)gbuf_rptr(m);
dupe = 0;
for (i=0; i<lzonecnt && !dupe; i++,pnve++) {
if (i && !(i%ZONES_PER_BLK))
if (gbuf_cont(m)) {
m = gbuf_cont(m);
pnve = (at_nvestr_t*)gbuf_rptr(m);
}
else
break;
if (pnew->len != pnve->len)
continue;
if ((pnew->len > 33) || (pnew->len <0) ) {
return(0);
}
if (!strncmp(pnew->str, pnve->str, pnew->len)) {
dupe=1;
continue;
}
}
if (!dupe) {
/* add new zone */
if (lzonecnt && !(lzonecnt%ZONES_PER_BLK)) {
if(!(gbuf_cont(m) = gbuf_alloc(ZONE_BLK_SIZE, PRI_MED)))
return(ENOBUFS);
gbuf_wset(gbuf_cont(m),0);
pnve = (at_nvestr_t*)gbuf_rptr(gbuf_cont(m));
}
strncpy(pnve->str,pnew->str,pnew->len);
pnve->len = pnew->len;
lzonecnt++;
}
bytesread += (pnew->len+1);
pnew = (at_nvestr_t*) (((char *)pnew) + pnew->len + 1);
}
/* showLocalZones1(); */
return(0);
}
/**********
showLocalZones1()
{
int i;
at_nvestr_t *pnve;
gbuf_t *m;
char str[35];
for (i=0; ; i++) {
if (!(pnve = getLocalZone(i))) {
break;
}
strncpy(str,pnve->str,pnve->len);
str[pnve->len] = '\0';
}
}
*********/
isZoneLocal(zone)
at_nvestr_t *zone;
{
at_nvestr_t *pnve;
int i;
if ((zone->len == 1 && zone->str[0] == '*') || zone->len == 0)
return(1);
for (i=0; ; i++) {
if (!(pnve = getLocalZone(i)))
break;
if (!nbp_strcmp(pnve,zone,0))
return(1);
}
return(0);
}
#define NULL_PNVESTR (at_nvestr_t *) 0
at_nvestr_t *getLocalZone(zno)
int zno; /* zone number in virtual list to
return, 0 for first zone */
/* returns pointer to a new local zone number zno,
returns null when no zones left.
*/
{
if_zone_t ifz;
ifz.ifzn.zone = zno;
if (ROUTING_MODE || MULTIHOME_MODE)
return(getRTRLocalZone(&ifz));
else
return(getSPLocalZone(zno));
}
at_nvestr_t *getSPLocalZone(zno)
int zno; /* zone number in virtual list to
return, 0 for first zone */
/* single port mode version */
{
int curz=0; /* current zone */
gbuf_t *m;
at_nvestr_t *pnve;
if (lzones) {
m = lzones;
pnve = (at_nvestr_t*)gbuf_rptr(m);
}
else
return(NULL_PNVESTR);
if ( zno>=lzonecnt )
return(NULL_PNVESTR);
for (curz=0; curz<zno; curz++,pnve++ ) {
if ( curz<lzonecnt ) {
if (curz && !(curz%ZONES_PER_BLK) ) {
if (gbuf_cont(m)) {
m = gbuf_cont(m);
pnve = (at_nvestr_t*)gbuf_rptr(m);
}
else {
return(NULL_PNVESTR);
}
}
if ((pnve->len > NBP_NVE_STR_SIZE) || (pnve->len <0) ) {
return(NULL_PNVESTR);
}
}
else
return(NULL_PNVESTR);
}
return(pnve);
}