Source to bsd/netat/aurp_zi.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) 1996 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.
*
* File: zi.c
*/
#include <sysglue.h>
#include <at/appletalk.h>
#include <lap.h>
#include <routing_tables.h>
#define _AURP
#include <at_aurp.h>
#include <at/aurp.h>
/* */
void AURPsndZReq(state)
aurp_state_t *state;
{
gbuf_t *m;
int msize;
aurp_hdr_t *hdrp;
short *net, nets_cnt, net_sent=0, entry_num=0;
RT_entry *entry = RT_table;
if (!state->get_zi || (state->rcv_state == AURPSTATE_Unconnected))
return;
l_more:
msize = sizeof(aurp_hdr_t);
if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZReq: node=%d, out of mblk\n",
state->rem_node));
return;
}
gbuf_wset(m,msize);
/* construct the ZI request packet */
hdrp = (aurp_hdr_t *)gbuf_rptr(m);
hdrp->connection_id = state->rcv_connection_id;
hdrp->sequence_number = 0;
hdrp->command_code = AURPCMD_ZReq;
hdrp->flags = 0;
*(short *)(hdrp+1) = AURPSUBCODE_ZoneInfo1;
gbuf_winc(m,sizeof(short));
net = (short *)gbuf_wptr(m);
nets_cnt = 0;
while (entry_num < RT_maxentry) {
/*
* scan the router table, and build the ZI request packet
* with the right entries, i.e.,
* - entry in use and not of the net_port
* - with no zones and in an active state
* - talking to the right router
*/
if ( (entry->NetPort == net_port) && entry->NetStop &&
((entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
(!RT_ALL_ZONES_KNOWN(entry)) ) {
*net++ = (entry->NetStart) ? entry->NetStart : entry->NetStop;
nets_cnt++;
}
if (nets_cnt >= 640) {
/* query only 640 networks per packet */
dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n",
state->rem_node));
gbuf_winc(m,(nets_cnt * sizeof(short)));
AURPsend(m, AUD_AURP, state->rem_node);
net_sent = 1;
goto l_more;
}
entry_num++;
entry++;
}
if (nets_cnt) {
dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n",
state->rem_node));
gbuf_winc(m,(nets_cnt * sizeof(short)));
AURPsend(m, AUD_AURP, state->rem_node);
net_sent = 1;
} else
gbuf_freeb(m);
if (!net_sent)
state->get_zi = 0;
}
/* */
void AURPsndZRsp(state, dat_m, flag)
aurp_state_t *state;
gbuf_t *dat_m;
int flag;
{
short len;
int msize, next_entry = 0;
gbuf_t *m;
aurp_hdr_t *hdrp;
if ((state->snd_state == AURPSTATE_Unconnected) || (dat_m == 0))
return;
msize = sizeof(aurp_hdr_t);
do {
if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZRsp: node=%d, out of mblk\n",
state->rem_node));
return;
}
gbuf_wset(m,msize);
/* construct the ZI response packet */
hdrp = (aurp_hdr_t *)gbuf_rptr(m);
hdrp->connection_id = state->snd_connection_id;
hdrp->sequence_number = 0;
hdrp->command_code = AURPCMD_ZRsp;
hdrp->flags = 0;
/* get zone info of the local networks */
next_entry = AURPgetzi(next_entry, gbuf_wptr(m), &len, dat_m, flag);
gbuf_winc(m,len);
/* send the packet */
dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZRsp: len=%d\n", len));
AURPsend(m, AUD_AURP, state->rem_node);
} while (next_entry);
gbuf_freem(dat_m);
}
/* */
void AURPsndGZN(state, dat_m)
aurp_state_t *state;
gbuf_t *dat_m;
{
short zname_len;
int msize;
gbuf_t *m;
aurp_hdr_t *hdrp;
if (state->snd_state == AURPSTATE_Unconnected)
return;
msize = sizeof(aurp_hdr_t);
if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGZN: node=%d, out of mblk\n",
state->rem_node));
return;
}
gbuf_wset(m,msize);
/* construct the GZN response packet */
hdrp = (aurp_hdr_t *)gbuf_rptr(m);
hdrp->connection_id = state->snd_connection_id;
hdrp->sequence_number = 0;
hdrp->command_code = AURPCMD_ZRsp;
hdrp->flags = 0;
*(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetZoneNets;
gbuf_winc(m,sizeof(short));
zname_len = gbuf_len(dat_m);
bcopy(gbuf_rptr(dat_m), gbuf_wptr(m), zname_len);
gbuf_winc(m,zname_len);
*(short *)(gbuf_wptr(m)) = -1; /* number of tuples - proto not supported */
gbuf_winc(m,sizeof(short));
/* send the packet */
dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGZN: count=%d\n", -1));
AURPsend(m, AUD_AURP, state->rem_node);
}
/* */
void AURPsndGDZL(state, dat_m)
aurp_state_t *state;
gbuf_t *dat_m;
{
int msize;
gbuf_t *m;
aurp_hdr_t *hdrp;
if (state->snd_state == AURPSTATE_Unconnected)
return;
msize = sizeof(aurp_hdr_t);
if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGDZL: node=%d, out of mblk\n",
state->rem_node));
return;
}
gbuf_wset(m,msize);
/* construct the GDZL response packet */
hdrp = (aurp_hdr_t *)gbuf_rptr(m);
hdrp->connection_id = state->snd_connection_id;
hdrp->sequence_number = 0;
hdrp->command_code = AURPCMD_ZRsp;
hdrp->flags = 0;
*(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetDomainZoneList;
gbuf_winc(m,sizeof(short));
*(short *)(gbuf_wptr(m)) = -1; /* start index - proto not supported */
gbuf_winc(m,sizeof(short));
/* send the packet */
dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGDZL: index=%d\n", -1));
AURPsend(m, AUD_AURP, state->rem_node);
}
/* */
void AURPrcvZReq(state, m)
aurp_state_t *state;
gbuf_t *m;
{
short sub_code;
aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m);
/* make sure we're in a valid state to accept it */
if (state->snd_state == AURPSTATE_Unconnected) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZReq: unexpected response\n"));
gbuf_freem(m);
return;
}
/* check for the correct connection id */
if (hdrp->connection_id != state->snd_connection_id) {
dPrintf(D_M_AURP, D_L_WARNING,
("AURPrcvZReq: invalid connection id, r=%d, m=%d\n",
hdrp->connection_id, state->snd_connection_id));
gbuf_freem(m);
return;
}
gbuf_rinc(m,sizeof(*hdrp));
sub_code = *(short *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(short));
dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZReq: len=%d\n", gbuf_len(m)));
switch (sub_code) {
case AURPSUBCODE_ZoneInfo1:
AURPsndZRsp(state, m, 0);
return;
case AURPSUBCODE_GetZoneNets:
AURPsndGZN(state, m);
break;
case AURPSUBCODE_GetDomainZoneList:
AURPsndGDZL(state, m);
break;
}
gbuf_freem(m);
}
/* */
void AURPrcvZRsp(state, m)
aurp_state_t *state;
gbuf_t *m;
{
short sub_code, tuples_cnt;
aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m);
/* make sure we're in a valid state to accept it */
if (state->rcv_state == AURPSTATE_Unconnected) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZRsp: unexpected response\n"));
gbuf_freem(m);
return;
}
/* check for the correct connection id */
if (hdrp->connection_id != state->rcv_connection_id) {
dPrintf(D_M_AURP, D_L_WARNING,
("AURPrcvZRsp: invalid connection id, r=%d, m=%d\n",
hdrp->connection_id, state->rcv_connection_id));
gbuf_freem(m);
return;
}
gbuf_rinc(m,sizeof(*hdrp));
sub_code = *(short *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(short));
dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZRsp: len=%d\n", gbuf_len(m)));
switch (sub_code) {
case AURPSUBCODE_ZoneInfo1:
case AURPSUBCODE_ZoneInfo2:
tuples_cnt = *(short *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(short));
if (AURPsetzi(state->rem_node, m, sub_code, tuples_cnt)) {
dPrintf(D_M_AURP, D_L_ERROR,
("AURPrcvZRsp: AURPsetzi() error\n"));
}
break;
case AURPSUBCODE_GetZoneNets:
break;
case AURPSUBCODE_GetDomainZoneList:
break;
}
gbuf_freem(m);
}
/* */
int AURPgetzi(next_entry, buf, len, dat_m, flag)
int next_entry;
unsigned char *buf;
short *len;
gbuf_t *dat_m;
int flag;
{
static int i_sav=ZT_BYTES-1, j_sav=0, idx_sav=-1;
unsigned char ev, zname_len, *zmap, *zname_base, *zname_sav, *tuples_ptr;
unsigned short net_num, *net, zname_offset;
short *sub_codep, *tuples_cntp, tuples_cnt, dat_len;
int i, j, idx, nets_cnt;
RT_entry *entry;
sub_codep = (short *)buf;
buf += sizeof(short);
tuples_cntp = (short *)buf;
buf += sizeof(short);
*len = sizeof(short) + sizeof(short);
zname_base = buf + sizeof(short);
dat_len = 0;
/* set the subcode in the ZI response packet */
*sub_codep = next_entry ? AURPSUBCODE_ZoneInfo2 : AURPSUBCODE_ZoneInfo1;
switch (flag) {
case 0: /* zone info in response to ZI request */
net = (unsigned short *)gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/2;
break;
case 1: /* zone info in response to Ack of RI response */
tuples_ptr = gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/3;
next_entry = 0;
break;
case 2: /* zone info in response to Ack of RI update */
tuples_ptr = gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/4;
next_entry = 0;
break;
}
/*
* for each network, find all the zones that it belongs to
*/
for (tuples_cnt=0; next_entry < nets_cnt; next_entry++) {
switch(flag) {
case 0:
net_num = net[next_entry];
break;
case 1:
net_num = *(unsigned short *)tuples_ptr;
tuples_ptr += 3;
gbuf_rinc(dat_m,3);
if (tuples_ptr[-1] & 0x80) {
tuples_ptr += 3;
gbuf_rinc(dat_m,3);
next_entry++;
}
break;
case 2:
if (gbuf_len(dat_m) <= 0) {
next_entry = nets_cnt;
goto l_done;
}
ev = *tuples_ptr++;
net_num = *(unsigned short *)tuples_ptr;
tuples_ptr += 3;
gbuf_rinc(dat_m,4);
if (tuples_ptr[-1] & 0x80) {
tuples_ptr += 2;
gbuf_rinc(dat_m,2);
}
if (ev != AURPEV_NetAdded)
continue;
break;
}
/*
* find the RT entry associated with the network
*/
if ((entry = RT_lookup(net_num)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPgetzi: invalid net, %d\n",
net_num));
continue;
}
if ( ((entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) ||
!RT_ALL_ZONES_KNOWN(entry) ||
(entry->AURPFlag & AURP_NetHiden) ) {
dPrintf(D_M_AURP_LOW, D_L_INFO, ("AURPgetzi: zombie net, net=%d\n",
net_num));
continue;
}
if (entry->NetStart == 0) {
if ((idx = ZT_get_zindex(entry->ZoneBitMap)) == 0)
continue;
idx--; /* index in the zone table */
zname_len = ZT_table[idx].Zone.len;
if (zname_len) {
*(unsigned short *)buf = net_num;
buf += sizeof(short);
if (idx == idx_sav) {
/* use the optimized format */
zname_offset = zname_sav - zname_base;
*(unsigned short *)buf = (0x8000 | zname_offset);
buf += sizeof(short);
dat_len += 4;
} else {
/* use the long format */
zname_sav = buf;
*buf++ = zname_len;
bcopy(ZT_table[idx].Zone.str, buf, zname_len);
buf += zname_len;
dat_len += (3 + zname_len);
}
tuples_cnt++;
idx_sav = idx;
}
} else {
zmap = entry->ZoneBitMap;
for (i=i_sav; i >=0; i--) {
if (!zmap[i])
continue;
for (j=j_sav; j < 8; j++) {
if (!((zmap[i] << j) & 0x80))
continue;
idx = i*8 + j; /* index in the zone table */
zname_len = ZT_table[idx].Zone.len;
if (zname_len) {
if ((dat_len+3+zname_len) > AURP_MaxPktSize) {
i_sav = i;
j_sav = j;
goto l_done;
}
*(unsigned short *)buf = net_num;
buf += sizeof(short);
if (idx == idx_sav) {
/* use the optimized format */
zname_offset = zname_sav - zname_base;
*(unsigned short *)buf = (0x8000 | zname_offset);
buf += sizeof(short);
dat_len += 4;
} else {
/* use the long format */
zname_sav = buf;
*buf++ = zname_len;
bcopy(ZT_table[idx].Zone.str, buf, zname_len);
buf += zname_len;
dat_len += (3 + zname_len);
}
tuples_cnt++;
idx_sav = idx;
}
}
}
}
if ((dat_len+3+32) > AURP_MaxPktSize) {
next_entry++;
break;
}
}
i_sav = ZT_BYTES-1;
j_sav = 0;
l_done:
*len += dat_len;
if (next_entry == nets_cnt)
next_entry = 0;
/* set the subcode in the ZI response packet */
if (next_entry)
*sub_codep = AURPSUBCODE_ZoneInfo2;
/* set the tuples count in the ZI response packet */
*tuples_cntp = tuples_cnt;
idx_sav = -1;
return next_entry;
}
/* */
int AURPsetzi(node, m, sub_code, tuples_cnt)
unsigned char node;
gbuf_t *m;
short sub_code;
short tuples_cnt;
{
int rc, tuple_fmt;
unsigned short net_num, zname_offset;
unsigned char *buf = gbuf_rptr(m), *zname_base;
RT_entry *entry;
at_nvestr_t *zname;
/* compute the base of the zone names of the optimized tuples */
zname_base = buf + sizeof(short);
/* process all tuples */
while (tuples_cnt-- > 0) {
net_num = *(unsigned short *)buf;
buf += sizeof(short);
if (*buf & 0x80) {
/* optimized-format tuple */
zname_offset = (*(unsigned short *)buf) & 0x7fff;
buf += sizeof(short);
zname = (at_nvestr_t *)(zname_base + zname_offset);
tuple_fmt = 0;
dPrintf(D_M_AURP_LOW, D_L_INFO,
("AURPsetzi: optimized fmt, net=%d. zlen=%d, zoffset=%d\n ",
net_num, zname->len, zname_offset));
} else {
/* long-format tuple */
zname = (at_nvestr_t *)buf;
tuple_fmt = 1;
dPrintf(D_M_AURP_LOW, D_L_INFO,
("AURPsetzi: long fmt, net=%d, zlen=%d\n ",
net_num, zname->len));
}
/*
* find the RT entry associated with the specified network
*/
if ((entry = RT_lookup(net_num)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING,
("AURPsetzi: invalid net, net=%d\n", net_num));
} else { /* entry found */
if (entry->EntryState >= RTE_STATE_SUSPECT) {
if ((rc = ZT_add_zname(zname)) == ZT_MAXEDOUT) {
dPrintf(D_M_AURP, D_L_WARNING,
("AURPsetzi: ZT_table full\n"));
} else {
ZT_set_zmap(rc, entry->ZoneBitMap);
RT_SET_ZONE_KNOWN(entry);
}
}
}
if (tuple_fmt)
buf += zname->len+1;
}
}