#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_llc.h>
#include <net/route.h>
#include <netccitt/dll.h>
#include <netccitt/llc_var.h>
char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC",
"UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"};
int llc_tracelevel = LLCTR_URGENT;
struct bitslice llc_bitslice[] = {
{ 0x1, 0x0 },
{ 0xfe, 0x1 },
{ 0x3, 0x0 },
{ 0xc, 0x2 },
{ 0x10, 0x4 },
{ 0xe0, 0x5 },
{ 0x1f, 0x0 }
};
struct llccb_q llccb_q = { &llccb_q, &llccb_q };
int af_link_rts_init_done = 0;
sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b)
{
if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b))
return(1);
return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data,
LLADDRLEN(sdl_a)));
}
sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t)
{
bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len);
}
sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b)
{
struct sockaddr_dl sdl_tmp;
sdl_copy(sdl_a, &sdl_tmp);
sdl_copy(sdl_b, sdl_a);
sdl_copy(&sdl_tmp, sdl_b);
}
struct sockaddr_dl *
sdl_getaddrif(struct ifnet *ifp)
{
register struct ifaddr *ifa;
for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == AF_LINK )
return((struct sockaddr_dl *)(ifa->ifa_addr));
return((struct sockaddr_dl *)0);
}
sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c)
{
register struct ifaddr *ifa;
for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
if ((ifa->ifa_addr->sa_family == AF_LINK ) &&
!sdl_cmp((struct sockaddr_dl *)(ifa->ifa_addr), sdl_c))
return(1);
return(0);
}
sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr,
u_char mac_len, struct sockaddr_dl *sdl_to)
{
register struct sockaddr_dl *sdl_tmp;
if ((sdl_tmp = sdl_getaddrif(ifp)) ) {
sdl_copy(sdl_tmp, sdl_to);
bcopy((caddr_t) mac_addr, (caddr_t) LLADDR(sdl_to), mac_len);
*(LLADDR(sdl_to)+mac_len) = dlsap_addr;
sdl_to->sdl_alen = mac_len+1;
return(1);
} else return(0);
}
sdl_sethdrif(struct ifnet *ifp, u_char *mac_src, u_char dlsap_src, u_char *mac_dst,
u_char dlsap_dst, u_char mac_len, struct sdl_hdr *sdlhdr_to)
{
if ( !sdl_setaddrif(ifp, mac_src, dlsap_src, mac_len,
&sdlhdr_to->sdlhdr_src) ||
!sdl_setaddrif(ifp, mac_dst, dlsap_dst, mac_len,
&sdlhdr_to->sdlhdr_dst) )
return(0);
else return(1);
}
static struct sockaddr_dl sap_saddr;
static struct sockaddr_dl sap_sgate = {
sizeof(struct sockaddr_dl),
AF_LINK
};
struct npaidbentry *
llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf)
{
struct protosw *pp;
struct sockaddr_dl *ifdl_addr;
struct rtentry *sirt = (struct rtentry *)0;
struct npaidbentry *sapinfo;
u_char saploc;
int size = sizeof(struct npaidbentry);
USES_AF_LINK_RTS;
pp = pffindtype (af, SOCK_STREAM);
if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) {
printf("network level protosw error");
return 0;
}
ifdl_addr = sdl_getaddrif(ifp);
sdl_copy(ifdl_addr, &sap_saddr);
sdl_copy(ifdl_addr, &sap_sgate);
saploc = LLSAPLOC(&sap_saddr, ifp);
sap_saddr.sdl_data[saploc] = sap;
sap_saddr.sdl_alen++;
rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr,
(struct sockaddr *)&sap_sgate, 0, 0, &sirt);
if (sirt == 0)
return 0;
MALLOC(sirt->rt_llinfo, caddr_t, size, M_PCB, M_WAITOK);
sapinfo = (struct npaidbentry *) sirt->rt_llinfo;
if (sapinfo) {
bzero ((caddr_t)sapinfo, size);
sapinfo->si_class = LLC_CLASS_II;
sapinfo->si_window = llconf->dllcfg_window;
sapinfo->si_trace = llconf->dllcfg_trace;
if (sapinfo->si_trace)
llc_tracelevel--;
else llc_tracelevel++;
sapinfo->si_input = pp->pr_input;
sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput;
return (sapinfo);
}
return 0;
}
struct npaidbentry *
llc_getsapinfo(u_char sap, struct ifnet *ifp)
{
struct sockaddr_dl *ifdl_addr;
struct sockaddr_dl si_addr;
struct rtentry *sirt;
u_char saploc;
USES_AF_LINK_RTS;
ifdl_addr = sdl_getaddrif(ifp);
sdl_copy(ifdl_addr, &si_addr);
saploc = LLSAPLOC(&si_addr, ifp);
si_addr.sdl_data[saploc] = sap;
si_addr.sdl_alen++;
if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0)))
sirt->rt_refcnt--;
else return(0);
return((struct npaidbentry *)sirt->rt_llinfo);
}
short
llc_seq2slot(struct llc_linkcb *linkp, short seqn)
{
register sn = 0;
sn = (linkp->llcl_freeslot + linkp->llcl_window -
(linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) %
LLC_MAX_SEQUENCE) % linkp->llcl_window;
return sn;
}
int
llc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case NL_CONNECT_REQUEST:
llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_SETFLAG(linkp, S, 0);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, SETUP);
break;
case LLCFT_SABME + LLC_CMD:
LLC_SETFLAG(linkp, F, pollfinal);
LLC_NEWSTATE(linkp, CONN);
action = LLC_CONNECT_INDICATION;
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
break;
default:
if (cmdrsp == LLC_CMD && pollfinal == 1)
llc_send(linkp, LLCFT_DM, LLC_RSP, 1);
}
return action;
}
int
llc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case NL_CONNECT_RESPONSE:
llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F));
LLC_RESETCOUNTER(linkp);
LLC_SETFLAG(linkp, P, 0);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
break;
case NL_DISCONNECT_REQUEST:
llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F));
LLC_NEWSTATE(linkp, ADM);
break;
case LLCFT_SABME + LLC_CMD:
LLC_SETFLAG(linkp, F, pollfinal);
break;
case LLCFT_DM + LLC_RSP:
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
}
return action;
}
int
llc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case NL_RESET_REQUEST:
if (LLC_GETFLAG(linkp, S) == 0) {
llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, RESET);
} else {
llc_send(linkp, LLCFT_UA, LLC_RSP,
LLC_GETFLAG(linkp, F));
LLC_RESETCOUNTER(linkp);
LLC_SETFLAG(linkp, P, 0);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_RESET_CONFIRM;
}
break;
case NL_DISCONNECT_REQUEST:
if (LLC_GETFLAG(linkp, S) == 0) {
llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, D_CONN);
} else {
llc_send(linkp, LLCFT_DM, LLC_RSP,
LLC_GETFLAG(linkp, F));
LLC_NEWSTATE(linkp, ADM);
}
break;
case LLCFT_DM + LLC_RSP:
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_SABME + LLC_CMD:
LLC_SETFLAG(linkp, S, 1);
LLC_SETFLAG(linkp, F, pollfinal);
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
}
return action;
}
int
llc_state_RESET_CHECK(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case NL_RESET_RESPONSE:
llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F));
LLC_RESETCOUNTER(linkp);
LLC_SETFLAG(linkp, P, 0);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
break;
case NL_DISCONNECT_REQUEST:
llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F));
LLC_NEWSTATE(linkp, ADM);
break;
case LLCFT_DM + LLC_RSP:
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_SABME + LLC_CMD:
LLC_SETFLAG(linkp, F, pollfinal);
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
}
return action;
}
int
llc_state_SETUP(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case LLCFT_SABME + LLC_CMD:
LLC_RESETCOUNTER(linkp);
llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
LLC_SETFLAG(linkp, S, 1);
break;
case LLCFT_UA + LLC_RSP:
if (LLC_GETFLAG(linkp, P) == pollfinal) {
LLC_STOP_ACK_TIMER(linkp);
LLC_RESETCOUNTER(linkp);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_CONNECT_CONFIRM;
}
break;
case LLC_ACK_TIMER_EXPIRED:
if (LLC_GETFLAG(linkp, S) == 1) {
LLC_SETFLAG(linkp, P, 0);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0),
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_CONNECT_CONFIRM;
} else if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry++;
} else {
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
}
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_DM + LLC_RSP:
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
}
return action;
}
int
llc_state_RESET(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case LLCFT_SABME + LLC_CMD:
LLC_RESETCOUNTER(linkp);
LLC_SETFLAG(linkp, S, 1);
llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
break;
case LLCFT_UA + LLC_RSP:
if (LLC_GETFLAG(linkp, P) == pollfinal) {
LLC_STOP_ACK_TIMER(linkp);
LLC_RESETCOUNTER(linkp);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_RESET_CONFIRM;
}
break;
case LLC_ACK_TIMER_EXPIRED:
if (LLC_GETFLAG(linkp, S) == 1) {
LLC_SETFLAG(linkp, P, 0);
LLC_SETFLAG(linkp, REMOTE_BUSY, 0);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_RESET_CONFIRM;
} else if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry++;
} else {
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
}
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_DM + LLC_RSP:
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
}
return action;
}
int
llc_state_D_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case LLCFT_SABME + LLC_CMD:
llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
break;
case LLCFT_UA + LLC_RSP:
if (LLC_GETFLAG(linkp, P) == pollfinal) {
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
}
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
break;
case LLCFT_DM + LLC_RSP:
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
break;
case LLC_ACK_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry++;
} else LLC_NEWSTATE(linkp, ADM);
break;
}
return action;
}
int
llc_state_ERROR(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case LLCFT_SABME + LLC_CMD:
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, RESET_CHECK);
action = LLC_RESET_INDICATION_REMOTE;
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_DM + LLC_RSP:
LLC_STOP_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_FRMR + LLC_RSP:
LLC_STOP_ACK_TIMER(linkp);
LLC_SETFLAG(linkp, S, 0);
LLC_NEWSTATE(linkp, RESET_WAIT);
action = LLC_FRMR_RECEIVED;
break;
case LLC_ACK_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry++;
} else {
LLC_SETFLAG(linkp, S, 0);
LLC_NEWSTATE(linkp, RESET_WAIT);
action = LLC_RESET_INDICATION_LOCAL;
}
break;
default:
if (cmdrsp == LLC_CMD){
llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal);
LLC_START_ACK_TIMER(linkp);
}
break;
}
return action;
}
int
llc_state_NBRAcore(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = 0;
switch(frame_kind + cmdrsp) {
case NL_DISCONNECT_REQUEST:
llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_STOP_ALL_TIMERS(linkp);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, D_CONN);
break;
case NL_RESET_REQUEST:
llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal);
LLC_SETFLAG(linkp, P, pollfinal);
LLC_STOP_ALL_TIMERS(linkp);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_SETFLAG(linkp, S, 0);
LLC_NEWSTATE(linkp, RESET);
break;
case LLCFT_SABME + LLC_CMD:
LLC_SETFLAG(linkp, F, pollfinal);
LLC_STOP_ALL_TIMERS(linkp);
LLC_NEWSTATE(linkp, RESET_CHECK);
action = LLC_RESET_INDICATION_REMOTE;
break;
case LLCFT_DISC + LLC_CMD:
llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
LLC_STOP_ALL_TIMERS(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLCFT_FRMR + LLC_RSP:
LLC_STOP_ALL_TIMERS(linkp);
LLC_SETFLAG(linkp, S, 0);
LLC_NEWSTATE(linkp, RESET_WAIT);
action = LLC_FRMR_RECEIVED;
break;
case LLCFT_DM + LLC_RSP:
LLC_STOP_ALL_TIMERS(linkp);
LLC_NEWSTATE(linkp, ADM);
action = LLC_DISCONNECT_INDICATION;
break;
case LLC_INVALID_NR + LLC_CMD:
case LLC_INVALID_NS + LLC_CMD:
LLC_SETFRMR(linkp, frame, cmdrsp,
(frame_kind == LLC_INVALID_NR ? LLC_FRMR_Z :
(LLC_FRMR_V | LLC_FRMR_W)));
llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal);
LLC_STOP_ALL_TIMERS(linkp);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, ERROR);
action = LLC_FRMR_SENT;
break;
case LLC_INVALID_NR + LLC_RSP:
case LLC_INVALID_NS + LLC_RSP:
case LLCFT_UA + LLC_RSP:
case LLC_BAD_PDU: {
char frmrcause = 0;
switch (frame_kind) {
case LLC_INVALID_NR: frmrcause = LLC_FRMR_Z; break;
case LLC_INVALID_NS: frmrcause = LLC_FRMR_V | LLC_FRMR_W; break;
default: frmrcause = LLC_FRMR_W;
}
LLC_SETFRMR(linkp, frame, cmdrsp, frmrcause);
llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0);
LLC_STOP_ALL_TIMERS(linkp);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, ERROR);
action = LLC_FRMR_SENT;
break;
}
default:
if (cmdrsp == LLC_RSP && pollfinal == 1 &&
LLC_GETFLAG(linkp, P) == 0) {
LLC_SETFRMR(linkp, frame, cmdrsp, LLC_FRMR_W);
LLC_STOP_ALL_TIMERS(linkp);
LLC_START_ACK_TIMER(linkp);
linkp->llcl_retry = 0;
LLC_NEWSTATE(linkp, ERROR);
action = LLC_FRMR_SENT;
}
break;
case LLC_P_TIMER_EXPIRED:
case LLC_ACK_TIMER_EXPIRED:
case LLC_REJ_TIMER_EXPIRED:
case LLC_BUSY_TIMER_EXPIRED:
if (linkp->llcl_retry >= llc_n2) {
LLC_STOP_ALL_TIMERS(linkp);
LLC_SETFLAG(linkp, S, 0);
LLC_NEWSTATE(linkp, RESET_WAIT);
action = LLC_RESET_INDICATION_LOCAL;
}
break;
}
return action;
}
int
llc_state_NORMAL(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case NL_DATA_REQUEST:
if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) {
#ifdef not_now
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_INFO, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
} else {
#endif
llc_send(linkp, LLCFT_INFO, LLC_CMD, 0);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
#ifdef not_now
}
#endif
action = 0;
}
break;
case LLC_LOCAL_BUSY_DETECTED:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_START_P_TIMER(linkp);
LLC_SETFLAG(linkp, DATA, 0);
LLC_NEWSTATE(linkp, BUSY);
action = 0;
} else {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_SETFLAG(linkp, DATA, 0);
LLC_NEWSTATE(linkp, BUSY);
action = 0;
}
break;
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_REJ, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
} else if (pollfinal == 0 && p == 1) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
} else if ((pollfinal == 0 && p == 0) ||
(pollfinal == 1 && p == 1 && cmdrsp == LLC_RSP)) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_P_TIMER(linkp);
LLC_START_REJ_TIMER(linkp);
if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else action = 0;
LLC_NEWSTATE(linkp, REJECT);
}
break;
}
case LLCFT_INFO + LLC_CMD:
case LLCFT_INFO + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_INC(linkp->llcl_vr);
LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0 && p == 1) {
LLC_INC(linkp->llcl_vr);
LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = LLC_DATA_INDICATION;
} else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) ||
(pollfinal == p && cmdrsp == LLC_RSP)) {
LLC_INC(linkp->llcl_vr);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (cmdrsp == LLC_RSP && pollfinal == 1)
LLC_CLEAR_REMOTE_BUSY(linkp, action);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_RR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if ((pollfinal == 0) ||
(cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) {
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
} else if ((pollfinal == 0) ||
(cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) {
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_REJ + LLC_CMD:
case LLCFT_REJ + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_resend(linkp, LLC_RSP, 1);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 0 && p == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) ||
(pollfinal == p && cmdrsp == LLC_RSP)) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_P_TIMER(linkp);
llc_resend(linkp, LLC_CMD, 1);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case NL_INITIATE_PF_CYCLE:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
action = 0;
}
break;
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
LLC_NEWSTATE(linkp, AWAIT);
action = 0;
}
break;
case LLC_ACK_TIMER_EXPIRED:
case LLC_BUSY_TIMER_EXPIRED:
if ((LLC_GETFLAG(linkp, P) == 0)
&& (linkp->llcl_retry < llc_n2)) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
LLC_NEWSTATE(linkp, AWAIT);
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_state_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case NL_DATA_REQUEST:
if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_INFO, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
action = 0;
} else {
llc_send(linkp, LLCFT_INFO, LLC_CMD, 0);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
action = 0;
}
break;
case LLC_LOCAL_BUSY_CLEARED: {
register int p = LLC_GETFLAG(linkp, P);
register int df = LLC_GETFLAG(linkp, DATA);
switch (df) {
case 1:
if (p == 0) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 1);
LLC_START_REJ_TIMER(linkp);
LLC_START_P_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
} else {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
}
break;
case 0:
if (p == 0) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_NEWSTATE(linkp, NORMAL);
action = 0;
} else {
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_NEWSTATE(linkp, NORMAL);
action = 0;
}
break;
case 2:
if (p == 0) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
} else {
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_NEWSTATE(linkp, REJECT);
action =0;
}
break;
}
break;
}
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 0)
LLC_SETFLAG(linkp, DATA, 1);
action = 0;
} else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) ||
(cmdrsp == LLC_RSP && pollfinal == p)) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 0)
LLC_SETFLAG(linkp, DATA, 1);
if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else action = 0;
} else if (pollfinal == 0 && p == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 0)
LLC_SETFLAG(linkp, DATA, 1);
action = 0;
}
break;
}
case LLCFT_INFO + LLC_CMD:
case LLCFT_INFO + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_INC(linkp->llcl_vr);
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 2)
LLC_STOP_REJ_TIMER(linkp);
LLC_SETFLAG(linkp, DATA, 0);
action = LLC_DATA_INDICATION;
} else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) ||
(cmdrsp == LLC_RSP && pollfinal == p)) {
LLC_INC(linkp->llcl_vr);
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 2)
LLC_STOP_REJ_TIMER(linkp);
if (cmdrsp == LLC_RSP && pollfinal == 1)
LLC_CLEAR_REMOTE_BUSY(linkp, action);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0 && p == 1) {
LLC_INC(linkp->llcl_vr);
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (LLC_GETFLAG(linkp, DATA) == 2)
LLC_STOP_REJ_TIMER(linkp);
LLC_SETFLAG(linkp, DATA, 0);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_RR + LLC_RSP:
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (frame_kind == LLCFT_RR) {
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else {
LLC_SET_REMOTE_BUSY(linkp, action);
}
} else if (pollfinal = 0 ||
(cmdrsp == LLC_RSP && pollfinal == 1)) {
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (frame_kind == LLCFT_RR) {
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else {
LLC_SET_REMOTE_BUSY(linkp, action);
}
}
break;
}
case LLCFT_REJ + LLC_CMD:
case LLCFT_REJ + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) ||
(cmdrsp == LLC_RSP && pollfinal == p)) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 0 && p == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case NL_INITIATE_PF_CYCLE:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
action = 0;
}
break;
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
LLC_NEWSTATE(linkp, AWAIT_BUSY);
action = 0;
}
break;
case LLC_ACK_TIMER_EXPIRED:
case LLC_BUSY_TIMER_EXPIRED:
if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
LLC_NEWSTATE(linkp, AWAIT_BUSY);
action = 0;
}
break;
case LLC_REJ_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2)
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
LLC_SETFLAG(linkp, DATA, 1);
LLC_NEWSTATE(linkp, AWAIT_BUSY);
action = 0;
} else{
LLC_SETFLAG(linkp, DATA, 1);
LLC_NEWSTATE(linkp, BUSY);
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_state_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case NL_DATA_REQUEST:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_INFO, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
} else {
llc_send(linkp, LLCFT_INFO, LLC_CMD, 0);
if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
LLC_START_ACK_TIMER(linkp);
LLC_NEWSTATE(linkp, REJECT);
action = 0;
}
break;
case NL_LOCAL_BUSY_DETECTED:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_SETFLAG(linkp, DATA, 2);
LLC_NEWSTATE(linkp, BUSY);
action = 0;
} else {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_SETFLAG(linkp, DATA, 2);
LLC_NEWSTATE(linkp, BUSY);
action = 0;
}
break;
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = 0;
} else if (pollfinal == 0 ||
(cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else action = 0;
}
break;
}
case LLCFT_INFO + LLC_CMD:
case LLCFT_INFO + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_INC(linkp->llcl_vr);
LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_STOP_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_DATA_INDICATION;
} else if ((cmdrsp = LLC_RSP && pollfinal == p) ||
(cmdrsp == LLC_CMD && pollfinal == 0 && p == 0)) {
LLC_INC(linkp->llcl_vr);
LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
if (cmdrsp == LLC_RSP && pollfinal == 1)
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_STOP_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0 && p == 1) {
LLC_INC(linkp->llcl_vr);
LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0);
LLC_STOP_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_RR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 0 ||
(cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) {
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 0 ||
(cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) {
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = 0;
}
break;
}
case LLCFT_REJ + LLC_CMD:
case LLCFT_REJ + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_resend(linkp, LLC_RSP, 1);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) ||
(cmdrsp == LLC_RSP && pollfinal == p)) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 0 && p == 1) {
linkp->llcl_vs = nr;
LLC_UPDATE_NR_RECEIVED(linkp, nr);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case NL_INITIATE_PF_CYCLE:
if (LLC_GETFLAG(linkp, P) == 0) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
action = 0;
}
break;
case LLC_REJ_TIMER_EXPIRED:
if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_START_REJ_TIMER(linkp);
linkp->llcl_retry++;
action = 0;
}
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_START_REJ_TIMER(linkp);
linkp->llcl_retry++;
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
}
break;
case LLC_ACK_TIMER_EXPIRED:
case LLC_BUSY_TIMER_EXPIRED:
if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_START_REJ_TIMER(linkp);
linkp->llcl_retry++;
linkp->llcl_vs = 0;
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_state_AWAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case LLC_LOCAL_BUSY_DETECTED:
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_SETFLAG(linkp, DATA, 0);
LLC_NEWSTATE(linkp, AWAIT_BUSY);
action = 0;
break;
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_REJ, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
llc_resend(linkp, LLC_CMD, 0);
LLC_START_REJ_TIMER(linkp);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, REJECT);
} else if (pollfinal == 0) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
}
break;
}
case LLCFT_INFO + LLC_RSP:
case LLCFT_INFO + LLC_CMD: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
LLC_INC(linkp->llcl_vr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = LLC_DATA_INDICATION;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
llc_resend(linkp, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_RR + LLC_RSP:
case LLCFT_REJ + LLC_CMD:
case LLCFT_REJ + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, NORMAL);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (pollfinal == 1 && cmdrsp == LLC_CMD) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
} else if (pollfinal == 1 && cmdrsp == LLC_RSP) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
LLC_SET_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, NORMAL);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
}
break;
}
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_state_AWAIT_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case LLC_LOCAL_BUSY_CLEARED:
switch (LLC_GETFLAG(linkp, DATA)) {
case 1:
llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
LLC_START_REJ_TIMER(linkp);
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
break;
case 0:
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_NEWSTATE(linkp, AWAIT);
action = 0;
break;
case 2:
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_NEWSTATE(linkp, AWAIT_REJECT);
action = 0;
break;
}
break;
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SETFLAG(linkp, DATA, 1);
action = 0;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
LLC_SETFLAG(linkp, DATA, 1);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
llc_resend(linkp, LLC_CMD, 0);
LLC_NEWSTATE(linkp, BUSY);
} else if (pollfinal == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SETFLAG(linkp, DATA, 1);
action = 0;
}
}
case LLCFT_INFO + LLC_CMD:
case LLCFT_INFO + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_INC(linkp->llcl_vr);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SETFLAG(linkp, DATA, 0);
action = LLC_DATA_INDICATION;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_INC(linkp->llcl_vr);
LLC_START_P_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_SETFLAG(linkp, DATA, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
llc_resend(linkp, LLC_CMD, 0);
LLC_NEWSTATE(linkp, BUSY);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_INC(linkp->llcl_vr);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SETFLAG(linkp, DATA, 0);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_REJ + LLC_CMD:
case LLCFT_RR + LLC_RSP:
case LLCFT_REJ + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, BUSY);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int p = LLC_GETFLAG(linkp, P);
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RNR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
LLC_SET_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, BUSY);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
}
break;
}
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_RNR, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_state_AWAIT_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
int action = LLC_PASSITON;
switch(frame_kind + cmdrsp) {
case LLC_LOCAL_BUSY_DETECTED:
llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
LLC_SETFLAG(linkp, DATA, 2);
LLC_NEWSTATE(linkp, AWAIT_BUSY);
action = 0;
break;
case LLC_INVALID_NS + LLC_CMD:
case LLC_INVALID_NS + LLC_RSP: {
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = 0;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
llc_resend(linkp, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, REJECT);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
action = 0;
}
break;
}
case LLCFT_INFO + LLC_CMD:
case LLCFT_INFO + LLC_RSP: {
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
LLC_INC(linkp->llcl_vr);
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_STOP_REJ_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_NEWSTATE(linkp, AWAIT);
action = LLC_DATA_INDICATION;
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_INC(linkp->llcl_vr);
LLC_STOP_P_TIMER(linkp);
LLC_STOP_REJ_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
llc_resend(linkp, LLC_CMD, 0);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, NORMAL);
action = LLC_DATA_INDICATION;
} else if (pollfinal == 0) {
LLC_INC(linkp->llcl_vr);
llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
LLC_STOP_REJ_TIMER(linkp);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_NEWSTATE(linkp, AWAIT);
action = LLC_DATA_INDICATION;
}
break;
}
case LLCFT_RR + LLC_CMD:
case LLCFT_REJ + LLC_CMD:
case LLCFT_RR + LLC_RSP:
case LLCFT_REJ + LLC_RSP: {
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
llc_resend(linkp, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, REJECT);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_CLEAR_REMOTE_BUSY(linkp, action);
}
break;
}
case LLCFT_RNR + LLC_CMD:
case LLCFT_RNR + LLC_RSP: {
register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
if (cmdrsp == LLC_CMD && pollfinal == 1) {
llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
} else if (cmdrsp == LLC_RSP && pollfinal == 1) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
linkp->llcl_vs = nr;
LLC_STOP_P_TIMER(linkp);
LLC_SET_REMOTE_BUSY(linkp, action);
LLC_NEWSTATE(linkp, REJECT);
} else if (pollfinal == 0) {
LLC_UPDATE_NR_RECEIVED(linkp, nr);
LLC_SET_REMOTE_BUSY(linkp, action);
}
break;
}
case LLC_P_TIMER_EXPIRED:
if (linkp->llcl_retry < llc_n2) {
llc_send(linkp, LLCFT_REJ, LLC_CMD, 1);
LLC_START_P_TIMER(linkp);
linkp->llcl_retry++;
action = 0;
}
break;
}
if (action == LLC_PASSITON)
action = llc_state_NBRAcore(linkp, frame, frame_kind,
cmdrsp, pollfinal);
return action;
}
int
llc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
int cmdrsp, int pollfinal)
{
register int action = 0;
LLC_STARTTIMER(linkp, AGE);
action = (*linkp->llcl_statehandler)(linkp, frame, frame_kind,
cmdrsp, pollfinal);
once_more_and_again:
switch (action) {
case LLC_CONNECT_INDICATION: {
int naction;
LLC_TRACE(linkp, LLCTR_INTERESTING, "CONNECT INDICATION");
linkp->llcl_nlnext =
(*linkp->llcl_sapinfo->si_ctlinput)
(PRC_CONNECT_INDICATION,
(struct sockaddr *) &linkp->llcl_addr, (caddr_t) linkp);
if (linkp->llcl_nlnext == 0)
naction = NL_DISCONNECT_REQUEST;
else naction = NL_CONNECT_RESPONSE;
action = (*linkp->llcl_statehandler)(linkp, frame, naction, 0, 0);
goto once_more_and_again;
}
case LLC_CONNECT_CONFIRM:
llc_start(linkp);
break;
case LLC_DISCONNECT_INDICATION:
LLC_TRACE(linkp, LLCTR_INTERESTING, "DISCONNECT INDICATION");
(*linkp->llcl_sapinfo->si_ctlinput)
(PRC_DISCONNECT_INDICATION,
(struct sockaddr *) &linkp->llcl_addr, linkp->llcl_nlnext);
break;
case LLC_RESET_CONFIRM:
case LLC_RESET_INDICATION_LOCAL:
break;
case LLC_RESET_INDICATION_REMOTE:
LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "RESET INDICATION (REMOTE)");
action = (*linkp->llcl_statehandler)(linkp, frame,
NL_RESET_RESPONSE, 0, 0);
goto once_more_and_again;
case LLC_FRMR_SENT:
LLC_TRACE(linkp, LLCTR_URGENT, "FRMR SENT");
break;
case LLC_FRMR_RECEIVED:
LLC_TRACE(linkp, LLCTR_URGEN, "FRMR RECEIVED");
action = (*linkp->llcl_statehandler)(linkp, frame,
NL_RESET_REQUEST, 0, 0);
goto once_more_and_again;
case LLC_REMOTE_BUSY:
LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY");
break;
case LLC_REMOTE_NOT_BUSY:
LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY CLEARED");
llc_start(linkp);
break;
}
return action;
}
llc_init()
{
llcintrq.ifq_maxlen = IFQ_MAXLEN;
}
void
llc_resetwindow(struct llc_linkcb *linkp)
{
register struct mbuf *mptr = (struct mbuf *) 0;
register struct mbuf *anchor = (struct mbuf *)0;
register short i;
if (linkp->llcl_slotsfree != linkp->llcl_window) {
i = llc_seq2slot(linkp, linkp->llcl_nr_received);
anchor = mptr = linkp->llcl_output_buffers[i];
for (; i != linkp->llcl_freeslot;
i = llc_seq2slot(linkp, i+1)) {
if (linkp->llcl_output_buffers[i]) {
mptr->m_nextpkt = linkp->llcl_output_buffers[i];
mptr = mptr->m_nextpkt;
} else panic("LLC2 window broken");
}
}
if (mptr)
mptr->m_nextpkt = (struct mbuf *) 0;
if (anchor != (struct mbuf *)0) {
for (i = 0, mptr = anchor; mptr != (struct mbuf *) 0; i++) {
linkp->llcl_output_buffers[i] = mptr;
mptr = mptr->m_nextpkt;
linkp->llcl_output_buffers[i]->m_nextpkt = (struct mbuf *)0;
}
linkp->llcl_freeslot = i;
} else linkp->llcl_freeslot = 0;
linkp->llcl_nr_received = 0;
linkp->llcl_projvs = linkp->llcl_freeslot;
return;
}
struct llc_linkcb *
llc_newlink(struct sockaddr_dl *dst, struct ifnet *ifp, struct rtentry *nlrt,
caddr_t nlnext, struct rtentry *llrt)
{
struct llc_linkcb *nlinkp;
u_char sap = LLSAPADDR(dst);
short llcwindow;
MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb),
M_PCB, M_NOWAIT);
if (nlinkp == 0)
return (NULL);
bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb));
sdl_copy(dst, &nlinkp->llcl_addr);
nlinkp->llcl_nlrt = nlrt;
nlinkp->llcl_nlnext = nlnext;
nlinkp->llcl_llrt = llrt;
nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL;
nlinkp->llcl_statehandler = llc_state_ADM;
nlinkp->llcl_if = ifp;
nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp);
if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0)
llcwindow = LLC_MAX_WINDOW;
MALLOC(nlinkp->llcl_output_buffers, struct mbuf **,
llcwindow*sizeof(struct mbuf *), M_PCB, M_NOWAIT);
if (nlinkp->llcl_output_buffers == 0) {
FREE(nlinkp, M_PCB);
return(NULL);
}
bzero((caddr_t)nlinkp->llcl_output_buffers,
llcwindow*sizeof(struct mbuf *));
nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow;
insque(nlinkp, &llccb_q);
return(nlinkp);
}
llc_dellink(struct llc_linkcb *linkp)
{
register struct mbuf *m;
register struct mbuf *n;
register struct npaidbentry *sapinfo = linkp->llcl_sapinfo;
register i;
if (linkp->llcl_nlnext && sapinfo->si_ctlinput)
(*sapinfo->si_ctlinput)
(PRC_DISCONNECT_INDICATION,
(struct sockaddr *)&linkp->llcl_addr, linkp->llcl_nlnext);
if (linkp->llcl_llrt)
((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link
= (struct llc_linkcb *) 0;
remque(linkp);
for (m = linkp->llcl_writeqh; m;) {
n = m->m_act;
m_freem(m);
m = n;
}
for(i = 0; i < linkp->llcl_window; i++)
if (linkp->llcl_output_buffers[i])
m_freem(linkp->llcl_output_buffers[i]);
FREE((caddr_t)linkp->llcl_output_buffers, M_PCB);
FREE((caddr_t)linkp, M_PCB);
}
llc_decode(struct llc* frame, struct llc_linkcb * linkp)
{
register int ft = LLC_BAD_PDU;
if ((frame->llc_control & 01) == 0) {
ft = LLCFT_INFO;
} else switch (frame->llc_control) {
case LLC_UI:
case LLC_UI_P: ft = LLC_UI; break;
case LLC_DM:
case LLC_DM_P: ft =LLCFT_DM; break;
case LLC_DISC:
case LLC_DISC_P: ft = LLCFT_DISC; break;
case LLC_UA:
case LLC_UA_P: ft = LLCFT_UA; break;
case LLC_SABME:
case LLC_SABME_P: ft = LLCFT_SABME; break;
case LLC_FRMR:
case LLC_FRMR_P: ft = LLCFT_FRMR; break;
case LLC_XID:
case LLC_XID_P: ft = LLCFT_XID; break;
case LLC_TEST:
case LLC_TEST_P: ft = LLCFT_TEST; break;
case LLC_RR: ft = LLCFT_RR; break;
case LLC_RNR: ft = LLCFT_RNR; break;
case LLC_REJ: ft = LLCFT_REJ; break;
}
if (linkp) {
switch (ft) {
case LLCFT_INFO:
if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) {
ft = LLC_INVALID_NS;
break;
}
case LLCFT_RR:
case LLCFT_RNR:
case LLCFT_REJ:
if (LLC_NR_VALID(linkp, LLCGBITS(frame->llc_control_ext,
s_nr)) == 0)
ft = LLC_INVALID_NR;
break;
}
}
return ft;
}
int
llc_anytimersup(struct llc_linkcb * linkp)
{
register int i;
FOR_ALL_LLC_TIMERS(i)
if (linkp->llcl_timers[i] > 0)
break;
if (i == LLC_AGE_SHIFT)
return 0;
else return 1;
}
#define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr)
#define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s
char *timer_names[] = {"ACK", "P", "BUSY", "REJ", "AGE"};
char *
llc_getstatename(struct llc_linkcb *linkp)
{
CHECK(linkp, ADM);
CHECK(linkp, CONN);
CHECK(linkp, RESET_WAIT);
CHECK(linkp, RESET_CHECK);
CHECK(linkp, SETUP);
CHECK(linkp, RESET);
CHECK(linkp, D_CONN);
CHECK(linkp, ERROR);
CHECK(linkp, NORMAL);
CHECK(linkp, BUSY);
CHECK(linkp, REJECT);
CHECK(linkp, AWAIT);
CHECK(linkp, AWAIT_BUSY);
CHECK(linkp, AWAIT_REJECT);
return "UNKNOWN - eh?";
}
void
llc_link_dump(struct llc_linkcb* linkp, const char *message)
{
register int i;
register char *state;
printf("if %s%d\n", linkp->llcl_if->if_name, linkp->llcl_if->if_unit);
printf(">> %s <<\n", message);
printf("llc addr ");
for (i = 0; i < (SAL(linkp)->sdl_alen)-2; i++)
printf("%x:", (char)*(LLADDR(SAL(linkp))+i) & 0xff);
printf("%x,", (char)*(LLADDR(SAL(linkp))+i) & 0xff);
printf("%x\n", (char)*(LLADDR(SAL(linkp))+i+1) & 0xff);
printf("state %s, ", llc_getstatename(linkp));
for (i = LLC_ACK_SHIFT; i < LLC_AGE_SHIFT; i++)
printf("%s-%c %d/", timer_names[i],
(linkp->llcl_timerflags & (1<<i) ? 'R' : 'S'),
linkp->llcl_timers[i]);
printf("%s-%c %d\n", timer_names[i], (linkp->llcl_timerflags & (1<<i) ?
'R' : 'S'), linkp->llcl_timers[i]);
printf("flags P %d/F %d/S %d/DATA %d/REMOTE_BUSY %d\n",
LLC_GETFLAG(linkp, P), LLC_GETFLAG(linkp, S),
LLC_GETFLAG(linkp, DATA), LLC_GETFLAG(linkp, REMOTE_BUSY));
printf("V(R) %d/V(S) %d/N(R) received %d/window %d/freeslot %d\n",
linkp->llcl_vs, linkp->llcl_vr, linkp->llcl_nr_received,
linkp->llcl_window, linkp->llcl_freeslot);
}
void
llc_trace(struct llc_linkcb *linkp, int level, const char *message)
{
if (linkp->llcl_sapinfo->si_trace && level > llc_tracelevel)
llc_link_dump(linkp, message);
return;
}