#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/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <kern/assert.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_var.h>
#include <netat/routing_tables.h>
#include <netat/at_pcb.h>
#include <netat/aurp.h>
#include <netat/debug.h>
static int AURPgetzi(int, unsigned char *, short *, gbuf_t *, int);
static void AURPsetzi(unsigned char, gbuf_t *, short, short);
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);
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) {
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) {
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);
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;
next_entry = AURPgetzi(next_entry, gbuf_wptr(m), &len, dat_m, flag);
gbuf_winc(m,len);
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);
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;
gbuf_winc(m,sizeof(short));
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);
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;
gbuf_winc(m,sizeof(short));
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);
if (state->snd_state == AURPSTATE_Unconnected) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZReq: unexpected response\n"));
gbuf_freem(m);
return;
}
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=%ld\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);
if (state->rcv_state == AURPSTATE_Unconnected) {
dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZRsp: unexpected response\n"));
gbuf_freem(m);
return;
}
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=%ld\n", gbuf_len(m)));
switch (sub_code) {
case AURPSUBCODE_ZoneInfo1:
case AURPSUBCODE_ZoneInfo2:
tuples_cnt = *(short *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(short));
AURPsetzi(state->rem_node, m, sub_code, tuples_cnt);
break;
case AURPSUBCODE_GetZoneNets:
break;
case AURPSUBCODE_GetDomainZoneList:
break;
}
gbuf_freem(m);
}
static 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;
zname_sav = tuples_ptr = (unsigned char *) 0xdeadbeef;
net = (unsigned short *) 0xdeadbeef;
net_num = 0xdead;
nets_cnt = 0xfeedface;
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;
*sub_codep = next_entry ? AURPSUBCODE_ZoneInfo2 : AURPSUBCODE_ZoneInfo1;
switch (flag) {
case 0:
net = (unsigned short *)gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/2;
break;
case 1:
tuples_ptr = gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/3;
next_entry = 0;
break;
case 2:
tuples_ptr = gbuf_rptr(dat_m);
nets_cnt = (gbuf_len(dat_m))/4;
next_entry = 0;
break;
}
assert(nets_cnt != 0xfeedface);
for (tuples_cnt=0; next_entry < nets_cnt; next_entry++) {
switch(flag) {
case 0:
assert(net != 0xdeadbeef);
net_num = net[next_entry];
break;
case 1:
assert(tuples_ptr != 0xdeadbeef);
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;
}
assert(tuples_ptr != 0xdeadbeef);
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;
}
assert(net_num != 0xdead);
if ((entry = rt_blookup(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_ent_zindex(entry->ZoneBitMap)) == 0)
continue;
idx--;
zname_len = ZT_table[idx].Zone.len;
if (zname_len) {
assert(net_num != 0xdead);
*(unsigned short *)buf = net_num;
buf += sizeof(short);
if (idx == idx_sav) {
assert(zname_sav != 0xdeadbeef);
zname_offset = zname_sav - zname_base;
*(unsigned short *)buf = (0x8000 | zname_offset);
buf += sizeof(short);
dat_len += 4;
} else {
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;
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;
}
assert(net_num != 0xdead);
*(unsigned short *)buf = net_num;
buf += sizeof(short);
if (idx == idx_sav) {
assert(zname_sav != 0xdeadbeef);
zname_offset = zname_sav - zname_base;
*(unsigned short *)buf = (0x8000 | zname_offset);
buf += sizeof(short);
dat_len += 4;
} else {
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;
if (next_entry)
*sub_codep = AURPSUBCODE_ZoneInfo2;
*tuples_cntp = tuples_cnt;
idx_sav = -1;
return next_entry;
}
static void
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;
zname_base = buf + sizeof(short);
while (tuples_cnt-- > 0) {
net_num = *(unsigned short *)buf;
buf += sizeof(short);
if (*buf & 0x80) {
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 {
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));
}
if ((entry = rt_blookup(net_num)) == 0) {
dPrintf(D_M_AURP, D_L_WARNING,
("AURPsetzi: invalid net, net=%d\n", net_num));
} else {
if (entry->EntryState >= RTE_STATE_SUSPECT) {
if ((rc = zt_add_zonename(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;
}
}