#include <string.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <net/if_types.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_pcb.h>
#include <netat/at_var.h>
#include <netat/ddp.h>
#include <netat/nbp.h>
#include <netat/zip.h>
#include <netat/rtmp.h>
#include <netat/routing_tables.h>
#include <netat/at_snmp.h>
#include <netat/debug.h>
#define DATA_DDP(mp) ((at_ddp_t *)(gbuf_rptr(mp)))
#define DATA_NBP(mp) ((at_nbp_t *)((DATA_DDP(mp))->data))
#define NVE_ENTRY(mp) (nve_entry_t *)(gbuf_rptr(mp))
#ifndef MIN
#define MIN(a,b) ((a)>(b)?(b):(a))
#endif
#define errno nbperrno
extern at_ifaddr_t *ifID_table[];
extern at_ifaddr_t *ifID_home;
TAILQ_HEAD(name_registry, _nve_) name_registry;
static int errno;
static gbuf_t *lzones=0;
static int lzonecnt=0;
static u_int hzonehash=0;
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_validate_n_hash(nbp_req_t *, int, int);
static nve_entry_t *nbp_search_nve(nbp_req_t *, at_ifaddr_t *);
static int isZoneLocal(at_nvestr_t *);
static int nbp_enum_gen (nve_entry_t *);
static void nbp_setup_hdr (nbp_req_t *);
static void nbp_upshift (u_char *, int);
static u_char *nbp2zone(at_nbp_t *, u_char *);
#define NVE_LOCK nve_lock
static long nbp_id_count = 0;
void sethzonehash(elapp)
at_ifaddr_t *elapp;
{
if (elapp->startup_zone.len) {
hzonehash = nbp_strhash(&elapp->startup_zone);
}
}
void nbp_shutdown(void)
{
register nve_entry_t *nve_entry, *nve_next;
for ((nve_entry = TAILQ_FIRST(&name_registry)); nve_entry; nve_entry = nve_next) {
nve_next = TAILQ_NEXT(nve_entry, nve_link);
nbp_delete_entry(nve_entry);
}
if (lzones) {
gbuf_freem(lzones);
lzonecnt = 0;
lzones = NULL;
}
}
static
u_char *nbp2zone(nbp, maxp)
at_nbp_t *nbp;
u_char *maxp;
{
u_char *p;
p = (u_char*)&nbp->tuple[0].enu_entity;
if (p >= maxp) return NULL;
p += (*p +1);
if (p >= maxp) return NULL;
p += (*p +1);
if (p >= maxp) return NULL;
if ((p + *p) >= maxp) return NULL;
return(p);
}
void nbp_input(m, ifID)
register gbuf_t *m;
register at_ifaddr_t *ifID;
{
register at_ddp_t *ddp = DATA_DDP(m);
register at_nbp_t *nbp = DATA_NBP(m);
register RT_entry *rt;
register int ddpSent = FALSE;
struct etalk_addr mcastAddr;
nbp_req_t nbp_req;
u_char *p;
if ((gbuf_type(m) != MT_DATA && gbuf_type(m) != MSG_DATA) ||
ddp->type != DDP_NBP) {
gbuf_freem(m);
return;
}
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_input 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;
dst_net = NET_VALUE(ddp->dst_net);
dPrintf(D_M_NBP_LOW, D_L_USR2, (" LKUP %s\n",
ifID != ifID_home ? "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];
strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
strlcpy(object,nbp_req.nve.object.str, sizeof(object));
strlcpy(type,nbp_req.nve.type.str, sizeof(type));
if (ifID != ifID_home)
dPrintf(D_M_NBP_LOW,D_L_USR2,
("nbp_LKUP for:%s:%s@%s", object, type, zone));
}
#endif
break;
case NBP_FWDRQ:
{
register int zhome=0;
register int zno, i;
register gbuf_t *m2;
register int error_found =0;
register at_ifaddr_t *ifIDorig;
if (!ROUTING_MODE)
break;
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
) {
if (rt->NetPort >= IF_TOTAL_MAX) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input:FWDREQ: bad port# from RT_table\n"));
error_found = TRUE;
break;
}
ifID = ifID_table[rt->NetPort];
if (!ifID) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input: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_input:FWDREQ: ifID offline (port %d)\n",
rt->NetPort));
error_found = TRUE;
break;
}
break;
}
}
if (error_found)
break;
if (!ifID) {
routing_needed(m, ifIDorig, TRUE);
ddpSent= TRUE;
break;
}
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
p = nbp2zone(nbp, (u_char *)gbuf_wptr(m));
if ((p == NULL) || !(zno = zt_find_zname((at_nvestr_t *)p))) {
dPrintf(D_M_NBP,D_L_WARNING,
("nbp_input: FWDRQ:zone not found\n"));
break;
}
if (isZoneLocal((at_nvestr_t*)p))
zhome = TRUE;
if (!zt_get_zmcast(ifID, (at_nvestr_t*)p, (char *)&mcastAddr)) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input: FDWREQ:zt_get_zmcast error\n"));
break;
}
if (zhome) {
if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input: 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_input: FWDRQ:loop back for us\n"));
nbp_input(m2, ifID_home);
}
if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
ddp_bit_reverse((unsigned char *)&mcastAddr);
ddp_router_output(m, ifID, ET_ADDR, 0, 0, &mcastAddr);
ddpSent = TRUE;
}
break;
case NBP_BRRQ:
{
register int zno;
register int ztind;
register int ztbit;
register int zhome=0;
register int i;
register gbuf_t *m2, *m3;
register int fromUs = FALSE;
register at_socket ourSkt = 0;
if ((!(MULTIHOME_MODE && FROM_US(ddp))) && !ROUTING_MODE) {
dPrintf(D_M_NBP,D_L_USR2,
("nbp_input: BRREQ:non router or MH local\n"));
break;
}
p = nbp2zone(nbp, (u_char *)gbuf_wptr(m));
if ((p == NULL) || !(zno = zt_find_zname((at_nvestr_t *)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;
}
if (FROM_US(ddp)){
fromUs = TRUE;
ourSkt = ddp->src_socket;
dPrintf(D_M_NBP,D_L_USR2,
("nbp_input:BRRQ from us net:%d\n",
(int)NET_VALUE(ddp->src_net)));
}
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))
continue;
ifID = ifID_table[rt->NetPort];
if (!ifID) {
dPrintf(D_M_NBP, D_L_ERROR,
("nbp_input:BRRQ: ifID %s\n",
!ifID ? "not found" : "invalid"));
break;
}
ddp = DATA_DDP(m);
ddp->src_node = ifID->ifThisNode.s_node;
NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
ddp->src_socket = NBP_SOCKET;
if (!(m2 = (gbuf_t *)gbuf_copym((gbuf_t *)m))) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input: BRREQ:gbuf_copym failed\n"));
break;
}
ddp = DATA_DDP(m2);
nbp = DATA_NBP(m2);
if (MULTIHOME_MODE && fromUs ) {
dPrintf(D_M_NBP,D_L_USR3,
("nbp_input: BRREQ: src changed to %d.%d.%d\n",
ifID->ifThisNode.s_net,
ifID->ifThisNode.s_node, ourSkt));
nbp->tuple[0].enu_addr.net = htons(ifID->ifThisNode.s_net);
nbp->tuple[0].enu_addr.node = ifID->ifThisNode.s_node;
nbp->tuple[0].enu_addr.socket = ourSkt;
ddp->src_socket = NBP_SOCKET;
}
#if DEBUG
else
dPrintf(D_M_NBP, D_L_USR3,
("nbp_input: BRREQ: not from us\n"));
#endif
dPrintf(D_M_NBP, D_L_USR3,
("nbp_input dist:%d\n", rt->NetDist));
if (rt->NetDist == 0) {
nbp->control = NBP_LKUP;
NET_ASSIGN(ddp->dst_net, 0);
ddp->dst_node = 255;
if (!zt_get_zmcast(ifID, (at_nvestr_t*)p, (char *)&mcastAddr)) {
dPrintf(D_M_NBP,D_L_ERROR,
("nbp_input: BRRQ:zt_get_zmcast error\n"));
break;
}
if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
ddp_bit_reverse((unsigned char *)&mcastAddr);
ddp_router_output(m2, ifID, ET_ADDR, 0, 0, &mcastAddr);
}
else {
ddp->dst_node = 0;
if (rt->NetStart == 0)
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_input: 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_input: BRRQ:loop back for us\n"));
nbp_input(m3, ifID_home);
break;
}
case NBP_LKUP_REPLY:
if (!ROUTING_MODE)
break;
dPrintf(D_M_NBP,D_L_WARNING,
("nbp_input: 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_input: unhandled pkt: type:%d\n", nbp->control));
routing_needed(m, ifID, TRUE);
ddpSent = TRUE;
break;
}
if (!ddpSent)
gbuf_freem(m);
return;
}
static int nbp_validate_n_hash (nbp_req, wild_ok, checkLocal)
register nbp_req_t *nbp_req;
register int wild_ok;
register int checkLocal;
{
register at_nvestr_t *object, *type, *zone;
at_nbptuple_t *tuple;
register int i, part_wild;
tuple = DATA_NBP(nbp_req->request)->tuple;
nbp_req->flags = 0;
#ifdef COMMENTED_OUT
{
int net,node,skt;
net = ntohs(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
object = (at_nvestr_t *)&tuple->enu_entity;
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) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: bad str len\n"));
errno = EINVAL;
return (-1);
}
#ifdef NBP_DEBUG
{
char xzone[35],xobject[35],xtype[35];
strlcpy(xzone,zone->str, sizeof(xzone));
strlcpy(xobject,object->str, sizeof(xobject));
strlcpy(xtype,type->str, sizeof(xtype));
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_validate: looking for %s:%s@%s\n",
xobject, xtype, xzone));
}
#endif
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];
strlcpy((char *)str,(char *)zone->str,sizeof(str));
dPrintf(D_M_NBP_LOW,D_L_WARNING,
("nbp_val_n_hash bad zone: %s\n", str));
errno = EINVAL;
return(-1);
}
if (!DEFAULT_ZONE(zone)) {
nbp_req->nve.zone_hash = nbp_strhash(& nbp_req->nve.zone);
}
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 {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: wild not okay\n"));
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) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: too many parts wild\n"));
errno = EINVAL;
return (-1);
} else
part_wild++;
} else {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: wild not okay2\n"));
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 {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: wild not okay3\n"));
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) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_val_n_hash: too many parts wild2\n"));
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];
strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
strlcpy(object,nbp_req.nve.object.str, sizeof(object));
strlcpy(type,nbp_req.nve.type.str, sizeof(type));
dPrintf(D_M_NBP_LOW,D_L_USR4,
("nbp_validate: after hash: %s:%s@%s\n",
object, type, zone));
}
#endif
return(0);
}
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];
}
}
u_int nbp_strhash (nvestr)
register at_nvestr_t *nvestr;
{
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((size_t)(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_ifaddr_t *ifID;
{
register nve_entry_t *nve_entry;
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
strlcpy(object,nbp_req.nve.object.str, sizeof(object));
strlcpy(type,nbp_req.nve.type.str, sizeof(type));
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
TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
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 {
at_nvestr_t *ezone=&nve_entry->zone;
at_nvestr_t *rzone=&nbp_req->nve.zone;
if (!DEFAULT_ZONE(rzone) && !DEFAULT_ZONE(ezone)) {
if (nbp_strcmp (rzone, ezone, 0) != 0)
continue;
}
else {
if (MULTIHOME_MODE && ifID &&
(nve_entry->address.net !=
ifID->ifThisNode.s_net)) {
dPrintf(D_M_NBP, D_L_USR4,
("nbp search ifID (%d) & req net (%d) not eq\n",
nve_entry->address.net,
ifID->ifThisNode.s_net));
continue;
}
#if DEBUG
if (ifID)
dPrintf(D_M_NBP, D_L_USR4,
("nbp search ifID (%d) & req net (%d) equal\n",
nve_entry->address.net,
ifID->ifThisNode.s_net));
#endif
}
}
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;
}
}
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
strlcpy(object,nbp_req.nve.object.str, sizeof(object));
strlcpy(type,nbp_req.nve.type.str, sizeof(type));
dPrintf(D_M_NBP_LOW, D_L_USR2,
("nbp_search: found %s:%s@%s net:%d\n",
object, type, zone, (int)nve_entry->address.net));
}
#endif
if (nbp_req->func != NULL) {
if ((*(nbp_req->func))(nbp_req, nve_entry) != 0) {
return (NULL);
}
} else
return (nve_entry);
}
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;
u_char *p;
tuple_size = nve_entry->object.len + 1 +
nve_entry->type.len + 1 +
2 +
sizeof (at_inet_t) + 1;
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)
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);
}
tuple = (at_nbptuple_t *)gbuf_wptr(nbp_req->response);
tuple->enu_addr.net = htons(nve_entry->address.net);
tuple->enu_addr.node = nve_entry->address.node;
tuple->enu_addr.socket = nve_entry->address.socket;
tuple->enu_enum = nve_entry->enumerator;
p = (u_char *)&tuple->enu_entity.object;
obj_len = nve_entry->object.len + 1;
bcopy(&nve_entry->object, p, obj_len);
p += obj_len;
type_len = nve_entry->type.len + 1;
bcopy(&nve_entry->type, p, type_len);
p += type_len;
p[0] = (u_char)1;
p[1] = '*';
nbp_req->space_unused -= tuple_size;
gbuf_winc(nbp_req->response, tuple_size);
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;
{
u_char ch1,ch2;
register int i1, i2;
register int reverse = 0;
register int left_index;
if (str1->len == 0 || str2->len == 0) {
return (-1);
}
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)) {
reverse++;
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 = DDP_NBP;
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_ASSIGN_NOSWAP(ddp->dst_net, nbp_req->nve.address.net);
nbp->control = NBP_LKUP_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);
}
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, FALSE);
nbp_req->response = NULL;
errno = status;
return(errno?-1:0);
}
void nbp_add_multicast(zone, ifID)
at_nvestr_t *zone;
at_ifaddr_t *ifID;
{
char data[ETHERNET_ADDR_LEN];
if (zone->str[0] == '*')
return;
{
char str[35];
strlcpy((char *)str,(char *)zone->str,sizeof(str));
dPrintf(D_M_NBP_LOW, D_L_USR3,
("nbp_add_multi getting mc for %s\n", str));
}
zt_get_zmcast(ifID, zone, data);
if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
ddp_bit_reverse((unsigned char *)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,
0, (u_int) ifID, ifID->ifName));
bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
(void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
}
int
getNbpTableSize(void)
{
register nve_entry_t *nve;
register int i=0;
for (nve = TAILQ_FIRST(&name_registry); nve; nve = TAILQ_NEXT(nve, nve_link), i++)
i++;
return(i);
}
int
getNbpTable(p, s, c)
snmpNbpEntry_t *p;
int s;
int c;
{
register nve_entry_t *nve;
register int i=0;
static int nextNo=0;
static nve_entry_t *next = (nve_entry_t*)NULL;
if (s && next && nextNo == s) {
nve = next;
i = nextNo;
}
else
nve = TAILQ_FIRST(&name_registry);
for ( ; nve && c ; nve = TAILQ_NEXT(nve, nve_link), p++,i++) {
if (i>= s) {
p->nbpe_object = nve->object;
p->nbpe_type = nve->type;
c--;
}
}
if (nve) {
next = nve;
nextNo = i;
} else {
next = (nve_entry_t*)NULL;
nextNo = 0;
}
return 0;
}
#define ZONES_PER_BLK 31
#define ZONE_BLK_SIZE ZONES_PER_BLK * sizeof(at_nvestr_t)
int setLocalZones(newzones, size)
at_nvestr_t *newzones;
int size;
{
int bytesread=0;
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) {
{
char str[35];
strlcpy((char *)str,(char *)pnew->str,sizeof(str));
}
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 > NBP_NVE_STR_SIZE) {
return(0);
}
if (!strncmp((char *)pnew->str, (char *)pnve->str, pnew->len)) {
dupe=1;
continue;
}
}
if (!dupe) {
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));
}
strlcpy((char *)pnve->str,(char *)pnew->str,sizeof(pnve->str));
pnve->len = pnew->len;
lzonecnt++;
}
bytesread += (pnew->len+1);
pnew = (at_nvestr_t*) (((char *)pnew) + pnew->len + 1);
}
return(0);
}
int
isZoneLocal(zone)
at_nvestr_t *zone;
{
at_nvestr_t *pnve;
int i;
if (DEFAULT_ZONE(zone))
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_usage_t ifz;
ifz.zone_index = zno;
if (MULTIPORT_MODE)
return(getRTRLocalZone(&ifz));
else
return(getSPLocalZone(zno));
}
at_nvestr_t *getSPLocalZone(zno)
int zno;
{
int curz=0;
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) {
return(NULL_PNVESTR);
}
}
else
return(NULL_PNVESTR);
}
return(pnve);
}
int nbp_fillin_nve(entity, nve)
at_entity_t *entity;
nve_entry_t *nve;
{
register int i;
if (entity->object.len > NBP_NVE_STR_SIZE ||
entity->type.len > NBP_NVE_STR_SIZE ||
entity->zone.len > NBP_NVE_STR_SIZE) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_fillin_nve: bad str len\n"));
errno = EINVAL;
return (-1);
}
nve->zone = entity->zone;
nve->zone_hash = 0;
if (!isZoneLocal(&entity->zone)) {
errno = EINVAL;
return(-1);
}
if (!DEFAULT_ZONE(&entity->zone))
nve->zone_hash = nbp_strhash(&nve->zone);
nve->object = entity->object;
nve->object_hash = 0;
if (entity->object.len == 1 &&
(entity->object.str[0] == NBP_ORD_WILDCARD ||
entity->object.str[0] == NBP_SPL_WILDCARD)) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_fillin_nve: wildcard\n"));
errno = EINVAL;
return (-1);
}
for (i = 0; i < entity->object.len; i++) {
if (entity->object.str[i] == NBP_SPL_WILDCARD) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_fillin_nve: wildcard2\n"));
errno = EINVAL;
return (-1);
}
}
nve->object_hash = nbp_strhash(&nve->object);
nve->type = entity->type;
nve->type_hash = 0;
if (entity->type.len == 1 &&
(entity->type.str[0] == NBP_ORD_WILDCARD ||
entity->type.str[0] == NBP_SPL_WILDCARD)) {
errno = EINVAL;
return (-1);
}
for (i = 0; i < entity->type.len; i++) {
if (entity->type.str[i] == NBP_SPL_WILDCARD) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_fillin_nve: wildcard3\n"));
errno = EINVAL;
return (-1);
}
}
nve->type_hash = nbp_strhash(&nve->type);
return(0);
}
nve_entry_t *nbp_find_nve(nve)
nve_entry_t *nve;
{
register nve_entry_t *nve_entry;
TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
if (nve->zone_hash &&
((nve->zone_hash != nve_entry->zone_hash) &&
(nve->zone_hash != hzonehash))) {
dPrintf(D_M_NBP_LOW,D_L_USR4,
("nbp_find_nve: no match for zone, req hash:%x\n",
nve->zone_hash));
continue;
}
if ((nve->object_hash) &&
(nve->object_hash != nve_entry->object_hash))
continue;
if ((nve->type_hash) &&
(nve->type_hash != nve_entry->type_hash))
continue;
return (nve_entry);
}
return (NULL);
}
static int nbp_enum_gen (nve_entry)
register nve_entry_t *nve_entry;
{
register int new_enum = 0;
register nve_entry_t *ne;
re_do:
TAILQ_FOREACH(ne, &name_registry, nve_link) {
if ((*(int *)&ne->address == *(int *)&nve_entry->address) &&
(ne->enumerator == new_enum)) {
if (new_enum == 255)
return(EADDRNOTAVAIL);
else {
new_enum++;
goto re_do;
}
}
}
nve_entry->enumerator = new_enum;
return (0);
}
int nbp_new_nve_entry(nve_entry, ifID)
nve_entry_t *nve_entry;
at_ifaddr_t *ifID;
{
gbuf_t *tag;
nve_entry_t *new_entry;
at_nvestr_t *zone;
int error;
if (!(valid_at_addr((at_inet_t *)&nve_entry->address))) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_new_nve_entry: valid_at_addr\n"));
return(EINVAL);
}
if ((error = nbp_enum_gen(nve_entry)))
return(error);
nve_entry->unique_nbp_id = ++nbp_id_count;
if ((tag = gbuf_alloc(sizeof(nve_entry_t), PRI_HI)) == NULL){
return(ENOBUFS);
}
gbuf_wset(tag, sizeof(nve_entry_t));
new_entry = (nve_entry_t *)gbuf_rptr(tag);
bcopy(nve_entry, new_entry, sizeof(nve_entry_t));
if (DEFAULT_ZONE(&nve_entry->zone)) {
if (!MULTIPORT_MODE && ifID_home->ifZoneName.str[0] == '*') {
zone = &ifID_home->startup_zone;
} else {
zone = &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;
new_entry->pid = proc_selfpid();
TAILQ_INSERT_TAIL(&name_registry, new_entry, nve_link);
at_state.flags |= AT_ST_NBP_CHANGED;
#ifdef NBP_DEBUG
{
char zone[35],object[35],type[35];
strlcpy(zone,nbp_req.nve.zone.str, sizeof(zone));
strlcpy(object,nbp_req.nve.object.str, sizeof(object));
strlcpy(type,nbp_req.nve.type.str, sizeof(type));
dPrintf(D_M_NBP_LOW, D_L_USR4,
("nbp_insert: adding %s:%s@%s addr:%d.%d ",
object, type, zone,
new_entry->address.net, new_entry->address.node));
}
#endif
nbp_add_multicast(&new_entry->zone, ifID);
return (0);
}
void nbp_delete_entry (nve_entry)
nve_entry_t *nve_entry;
{
TAILQ_REMOVE(&name_registry, nve_entry, nve_link);
gbuf_freem(nve_entry->tag);
at_state.flags |= AT_ST_NBP_CHANGED;
}
int nbp_mh_reg(nbpP)
at_nbp_reg_t *nbpP;
{
nve_entry_t nve;
at_ifaddr_t *ifID = 0;
int registered = 0;
int finished = FALSE;
if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_mh_reg: bad tuple\n"));
return(EINVAL);
}
nve.address = nbpP->addr;
nve.ddptype = nbpP->ddptype;
if (DEFAULT_ZONE(&nbpP->name.zone)) {
TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
if (nbpP->addr.net || nbpP->addr.node) {
if ((nbpP->addr.net != ifID->ifThisNode.s_net ||
nbpP->addr.node != ifID->ifThisNode.s_node))
continue;
else
finished = TRUE;
} else {
nve.address.net = ifID->ifThisNode.s_net;
nve.address.node = ifID->ifThisNode.s_node;
}
nve.zone = ifID->ifZoneName;
nve.zone_hash = nbp_strhash(&nve.zone);
if (nbp_find_nve(&nve))
continue;
if (nbp_new_nve_entry(&nve, ifID) == 0)
registered++;
}
if (registered && !nbpP->addr.net && !nbpP->addr.node) {
nbpP->addr.net = ifID_home->ifThisNode.s_net;
nbpP->addr.node = ifID_home->ifThisNode.s_node;
}
} else {
int zno;
at_ifnames_t ifs_in_zone;
if (!(zno = zt_find_zname(&nve.zone))) {
dPrintf(D_M_NBP_LOW, D_L_WARNING,
("nbp_mh_reg: didn't find zone name\n"));
return(EINVAL);
}
getIfUsage(zno-1, &ifs_in_zone);
TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
if (!ifs_in_zone.at_if[ifID->ifPort])
continue;
else
finished = TRUE;
if (nbpP->addr.net || nbpP->addr.node) {
finished = FALSE;
if ((nbpP->addr.net != ifID->ifThisNode.s_net ||
nbpP->addr.node != ifID->ifThisNode.s_node))
continue;
else
finished = TRUE;
} else {
nve.address.net = ifID->ifThisNode.s_net;
nve.address.node = ifID->ifThisNode.s_node;
}
if (nbp_find_nve(&nve))
continue;
if (nbp_new_nve_entry(&nve, ifID) == 0)
registered++;
if (registered && !nbpP->addr.net && !nbpP->addr.node) {
nbpP->addr.net = ifID->ifThisNode.s_net;
nbpP->addr.node = ifID->ifThisNode.s_node;
}
}
}
nbpP->unique_nbp_id = (registered > 1)? 0: nve.unique_nbp_id;
if (registered)
return(0);
else
return(EADDRNOTAVAIL);
}