📄 hd_input.c
字号:
/* * This section tests the IFRAME for proper sequence. That is, it's * sequence number N(S) MUST be equal to V(S). */ if (ns != hdp->hd_vr) { hdp->hd_invalid_ns++; if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) { hdp->hd_condition |= REJ_CONDITION; /* * Flush the transmit queue. This is ugly but we * have no choice. A reject response must be * immediately sent to the DCE. Failure to do so * may result in another out of sequence iframe * arriving (and thus sending another reject) * before the first reject is transmitted. This * will cause the DCE to receive two or more * rejects back to back, which must never happen. */ hd_flush (hdp->hd_ifp); hd_writeinternal (hdp, REJ, pf); } return (queued); } hdp->hd_condition &= ~REJ_CONDITION; /* * This section finally tests the IFRAME's sequence number against * the window size (K) and the sequence number of the last frame * we have acknowledged. If the IFRAME is completely correct then * it is queued for the packet level. */ if (ns != (hdp -> hd_lasttxnr + hdp -> hd_xcp -> xc_lwsize) % MODULUS) { hdp -> hd_vr = (hdp -> hd_vr + 1) % MODULUS; if (pf == 1) { /* Must generate a RR or RNR with final bit on. */ hd_writeinternal (hdp, RR, POLLON); } else /* * Hopefully we can piggyback the RR, if not we will generate * a RR when T3 timer expires. */ if (hdp -> hd_rrtimer == 0) hdp->hd_rrtimer = hd_t3; /* Forward iframe to packet level of X.25. */ fbuf -> m_data += HDHEADERLN; fbuf -> m_len -= HDHEADERLN; fbuf -> m_pkthdr.len -= HDHEADERLN; fbuf -> m_pkthdr.rcvif = (struct ifnet *)hdp -> hd_pkp;#ifdef BSD4_3 fbuf->m_act = 0; /* probably not necessary */#else { register struct mbuf *m; for (m = fbuf; m -> m_next; m = m -> m_next) m -> m_act = (struct mbuf *) 0; m -> m_act = (struct mbuf *) 1; }#endif pk_input (fbuf); queued = TRUE; hd_start (hdp); } else { /* * Here if the remote station has transmitted more iframes then * the number which have been acknowledged plus K. */ hdp->hd_invalid_ns++; frame_reject (hdp, W, frame); } return (queued);}/* * This routine is used to determine if a value (the middle parameter) * is between two other values. The low value is the first parameter * the high value is the last parameter. The routine checks the middle * value to see if it is within the range of the first and last values. * The reason we need this routine is the values are modulo some base * hence a simple test for greater or less than is not sufficient. */boolrange_check (rear, value, front)int rear, value, front;{ register bool result = FALSE; if (front > rear) result = (rear <= value) && (value <= front); else result = (rear <= value) || (value <= front); return (result);}/* * This routine handles all the frame reject conditions which can * arise as a result of secondary processing. The frame reject * condition Y (frame length error) are handled elsewhere. */staticframe_reject (hdp, rejectcode, frame)struct hdcb *hdp;struct Hdlc_iframe *frame;{ register struct Frmr_frame *frmr = &hd_frmr; frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control; frmr -> frmr_ns = frame -> ns; frmr -> frmr_f1_0 = 0; frmr -> frmr_nr = frame -> nr; frmr -> frmr_f2_0 = 0; frmr -> frmr_0000 = 0; frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y = frmr -> frmr_z = 0; switch (rejectcode) { case Z: frmr -> frmr_z = 1;/* invalid N(R). */ break; case Y: frmr -> frmr_y = 1;/* iframe length error. */ break; case X: frmr -> frmr_x = 1;/* invalid information field. */ frmr -> frmr_w = 1; break; case W: frmr -> frmr_w = 1;/* invalid N(S). */ } hd_writeinternal (hdp, FRMR, POLLOFF); hdp->hd_state = WAIT_SABM; SET_TIMER (hdp);}/* * This procedure is invoked when ever we receive a supervisor * frame such as RR, RNR and REJ. All processing for these * frames is done here. */process_sframe (hdp, frame, frametype)register struct hdcb *hdp;register struct Hdlc_sframe *frame;int frametype;{ register int nr = frame -> nr, pf = frame -> pf, pollbit = 0; if (valid_nr (hdp, nr, pf) == TRUE) { switch (frametype) { case RR: hdp->hd_condition &= ~REMOTE_RNR_CONDITION; break; case RNR: hdp->hd_condition |= REMOTE_RNR_CONDITION; hdp->hd_retxcnt = 0; break; case REJ: hdp->hd_condition &= ~REMOTE_RNR_CONDITION; rej_routine (hdp, nr); } if (pf == 1) { hdp->hd_retxcnt = 0; hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION; if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs && hdp->hd_timer == 0 && hdp->hd_txq.head == 0) hd_writeinternal(hdp, RR, pf); else /* If any iframes have been queued because of the timer condition, transmit then now. */ if (hdp->hd_condition & REMOTE_RNR_CONDITION) { /* Remote is busy or timer condition, so only send one. */ if (hdp->hd_vs != hdp->hd_retxqi) hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit); } else /* Flush the retransmit list first. */ while (hdp->hd_vs != hdp->hd_retxqi) hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); } hd_start (hdp); } else frame_reject (hdp, Z, (struct Hdlc_iframe *)frame); /* Invalid N(R). */}/* * This routine tests the validity of the N(R) which we have received. * If it is ok, then all the iframes which it acknowledges (if any) * will be freed. */boolvalid_nr (hdp, nr, finalbit)register struct hdcb *hdp;register int finalbit;{ /* Make sure it really does acknowledge something. */ if (hdp->hd_lastrxnr == nr) return (TRUE); /* * This section validates the frame's N(R) value. It's N(R) value * must be in syncronization with our V(S) value and our "last * received nr" variable. If it is correct then we are able to send * more IFRAME's, else frame reject condition is entered. */ if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) { if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE) hdp->hd_vs = nr; else { hdp->hd_invalid_nr++; return (FALSE); } } /* * If we get to here, we do have a valid frame but it might be out * of sequence. However, we should still accept the receive state * number N(R) since it has already passed our previous test and it * does acknowledge frames which we are sending. */ KILL_TIMER (hdp); free_iframes (hdp, &nr, finalbit);/* Free all acknowledged iframes */ if (nr != hdp->hd_vs) SET_TIMER (hdp); return (TRUE);}/* * This routine determines how many iframes need to be retransmitted. * It then resets the Send State Variable V(S) to accomplish this. */staticrej_routine (hdp, rejnr)register struct hdcb *hdp;register int rejnr;{ register int anchor; /* * Flush the output queue. Any iframes queued for * transmission will be out of sequence. */ hd_flush (hdp->hd_ifp); /* * Determine how many frames should be re-transmitted. In the case * of a normal REJ this should be 1 to K. In the case of a timer * recovery REJ (ie. a REJ with the Final Bit on) this could be 0. */ anchor = hdp->hd_vs; if (hdp->hd_condition & TIMER_RECOVERY_CONDITION) anchor = hdp->hd_xx; anchor = (anchor - rejnr + 8) % MODULUS; if (anchor > 0) { /* There is at least one iframe to retransmit. */ KILL_TIMER (hdp); hdp->hd_vs = rejnr; while (hdp->hd_vs != hdp->hd_retxqi) hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); } hd_start (hdp);}/* * This routine frees iframes from the retransmit queue. It is called * when a previously written iframe is acknowledged. */staticfree_iframes (hdp, nr, finalbit)register struct hdcb *hdp;int *nr;register int finalbit;{ register int i, k; /* * We need to do the following because of a funny quirk in the * protocol. This case occures when in Timer recovery condition * we get a N(R) which acknowledges all the outstanding iframes * but with the Final Bit off. In this case we need to save the last * iframe for possible retransmission even though it has already been * acknowledged! */ if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) { *nr = (*nr - 1 + 8) % MODULUS;/* printf ("QUIRK\n"); */ } k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS; /* Loop here freeing all acknowledged iframes. */ for (i = 0; i < k; ++i) { m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]); hdp->hd_retxq[hdp->hd_lastrxnr] = 0; hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -