📄 llc_subr.c
字号:
* AWAIT_REJECT --- A data link connection exists between the local LLC service * access point and the remote LLC service access point. The * local connection component has requested that the remote * connection component re-transmit a specific I PDU that the * local connection component has detected as being out of * sequence. Before the local LLC entered this state it was * performing a timer recovery operation and had sent a * command PDU with the P bit set to ``1'', and is still * awaiting an acknowledgment from the remote LLC. I PDUs may * be received but not transmitted. Supervisory PDUs may be * both transmitted and received. */intllc_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;}/* * llc_statehandler() --- Wrapper for llc_state_*() functions. * Deals with action codes and checks for * ``stuck'' links. */intllc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, int cmdrsp, int pollfinal){ register int action = 0; /* * To check for ``zombie'' links each time llc_statehandler() gets called * the AGE timer of linkp is reset. If it expires llc_timer() will * take care of the link --- i.e. kill it 8=) */ LLC_STARTTIMER(linkp, AGE); /* * Now call the current statehandler function. */ 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_resend(linkp, LLC_CMD, 0); */ 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; /* internally visible only */ case LLC_RESET_CONFIRM: case LLC_RESET_INDICATION_LOCAL: /* * not much we can do here, the state machine either makes it or * brakes it ... */ 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"); /* * try to get queued frames out */ llc_start(linkp); break; } /* * Only LLC_DATA_INDICATION is for the time being * passed up to the network layer entity. * The remaining action codes are for the time * being visible internally only. * However, this can/may be changed if necessary. */ return action;}/* * Core LLC2 routines */ /* * The INIT call. This routine is called once after the system is booted. */llc_init(){ llcintrq.ifq_maxlen = IFQ_MAXLEN;}/* * In case of a link reset we need to shuffle the frames queued inside the * LLC2 window. */voidllc_resetwindow(struct llc_linkcb *linkp){ register struct mbuf *mptr = (struct mbuf *) 0; register struct mbuf *anchor = (struct mbuf *)0; register short i; /* Pick up all queued frames and collect them in a linked mbuf list */ 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"); } } /* clean closure */ if (mptr) mptr->m_nextpkt = (struct mbuf *) 0; /* Now --- plug 'em in again */ 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; /* We're resetting the link, the next frame to be acknowledged is 0 */ linkp->llcl_nr_received = 0; /* set distance between LLC2 sequence number and the top of window to 0 */ linkp->llcl_projvs = linkp->llcl_freeslot; return;} /* * llc_newlink() --- We allocate enough memory to contain a link control block * and initialize it properly. We don't intiate the actual setup * of the LLC2 link here. */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; /* allocate memory for link control block */ MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb), M_PCB, M_DONTWAIT); if (nlinkp == 0) return (NULL); bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb)); /* copy link address */ sdl_copy(dst, &nlinkp->llcl_addr); /* hold on to the network layer route entry */ nlinkp->llcl_nlrt = nlrt; /* likewise the network layer control block */ nlinkp->llcl_nlnext = nlnext; /* jot down the link layer route entry */ nlinkp->llcl_llrt = llrt; /* reset writeq */ nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL; /* setup initial state handler function */ nlinkp->llcl_statehandler = llc_state_ADM; /* hold on to interface pointer */ nlinkp->llcl_if = ifp; /* get service access point information */ nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp); /* get window size from SAP info block */ if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0) llcwindow = LLC_MAX_WINDOW; /* allocate memory for window buffer */ MALLOC(nlinkp->llcl_output_buffers, struct mbuf **, llcwindow*sizeof(struct mbuf *), M_PCB, M_DONTWAIT); if (nlinkp->llcl_output_buffers == 0) { FREE(nlinkp, M_PCB); return(NULL); } bzero((caddr_t)nlinkp->llcl_output_buffers, llcwindow*sizeof(struct mbuf *)); /* set window size & slotsfree */ nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow; /* enter into linked listed of link control blocks */ insque(nlinkp, &llccb_q); return(nlinkp);}/* * llc_dellink() --- farewell to link control block */llc_dellink(struct llc_linkcb *linkp){ register struct mbuf *m; register struct mbuf *n; register struct npaidbentry *sapinfo = linkp->llcl_sapinfo; register i; /* notify upper layer of imminent death */ if (linkp->llcl_nlnext && sapinfo->si_ctlinput) (*sapinfo->si_ctlinput) (PRC_DISCONNECT_INDICATION, (struct sockaddr *)&linkp->llcl_addr, linkp->llcl_nlnext); /* pull the plug */ if (linkp->llcl_llrt) ((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link = (struct llc_linkcb *) 0; /* leave link control block queue */ remque(linkp); /* drop queued packets */ for (m = linkp->llcl_writeqh; m;) { n = m->m_act; m_freem(m); m = n; } /* drop packets in the window */ for(i = 0; i < linkp->llcl_window; i++) if (linkp->llcl_output_buffers[i]) m_freem(linkp->llcl_output_buffers[i]); /* return the window space */ FREE((caddr_t)linkp->llcl_output_buffers, M_PCB); /* return the control block space --- now it's gone ... */ 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; /* S or U frame ? */ } else switch (frame->llc_control) { /* U frames */ 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; /* S frames */ case LLC_RR: ft = LLCFT_RR; break; case LLC_RNR: ft = LLCFT_RNR; break; case LLC_REJ: ft = LLCFT_REJ; break; } /* switch */ if (linkp) { switch (ft) { case LLCFT_INFO: if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) { ft = LLC_INVALID_NS; break; } /* fall thru --- yeeeeeee */ case LLCF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -