📄 bsc_states.c
字号:
#ifndef lintstatic char *sccsid = "@(#)bsc_states.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* bsc_states.c U. Sinkewicz 1.0 5/10/85 * * Protocol state processing for the* * 2780/3780 Emulator. * * *//**************************************************************************** * Input to bsc_output: comes from the socket and is an mbuf with data to * transmit but no control characters. * Input to bsc_input: comes from the driver is bisync framed data in an mbuf * chain. * Output from bsc_output: goes to the driver and is several mbufs of * different sizes that contain both data and control * characters. * Output from bsc_input: goes to the socket and is an mbuf stripped of * everything but data. ****************************************************************************/#include "../h/param.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/buf.h"#include "../h/cpudata.h"#include "../h/conf.h"#include "../h/proc.h"#include "../h/mbuf.h"#include "../h/kernel.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../net/net/if.h"#include "../net/netbsc/bsc.h"#include "../net/net/route.h"#include "../net/netbsc/bsc_var.h"#include "../net/netbsc/bsc_states.h"#include "../net/netbsc/bsc_messages.h"#include "../net/netbsc/bsc_timer.h"#include "../h/errno.h"#include "../h/protosw.h"#include "../h/types.h"#include "../h/ioctl.h"#include "../h/uio.h"unsigned short crctable[16]={0x0000,0xcc01,0xd801,0x1400,0xf001,0x3c00, 0x2800,0xe401,0xa001,0x6c00,0x7800,0xb401, 0x5000,0x9c01,0x8801,0x4400};int flag;unsigned char crc[2];char xfcs0, xfcs1, rfcs0, rfcs1;char byte, rcvs, xbcb, rbcb, xseq, ackseq;char c1, nakctr, count, punch, rseq, actseq; /* nakctr is number of NAKs * rcvd for one sent block */short waiting, exitval, seqst;short ct0, ct1;int bsc_mbuf_len; /* The number of data characters you can fit * into m_up_ptr. */struct mbuf *m_up; /* Mbuf that contains processed data destined * for the socket. Characters from m_dvr * (mbuf from the driver) are copied into * m_up (mbuf going up to the socket). * Control characters and the crc * characters are eleminated. Passed up to * socket. */struct mbuf *m_up_ptr; /* Pointer to the one mbuf in the m_up chain * that we're currently working with. */struct bsc_data *dat_up; /* Pointer to data area of m_up. */int data_loc_up; /* Location in the m_up_ptr buffer where you * are currently writing a character. */struct bsc_data *dat_dvr; /* Pointer to data area of m_dvr. */int data_loc_dvr; /* What byte we're currently reading in the * data area of m_dvr. */struct mbuf *m_dvr; /* Contains raw data from the driver. * Comes from bscintr(). */struct mbuf *m_out; /* Contains data and control characters that * go to the driver. */struct bsc_ifaddr *bsc_ifaddr;bsc_output(bsc ) register struct bscpcb *bsc;{ struct sockaddr_bsc *sin = &bsc->bscp_laddr; struct sockaddr_bsc *dst; register struct bsc_ifaddr *bia; struct ifaddr *ifa; register struct ifnet *ifp; extern short state; int error; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0) return(EADDRNOTAVAIL); bia = (struct bsc_ifaddr *)bsc_biafinder( ifp ); if (bia == 0) return(EADDRNOTAVAIL); crcloc(); switch(state){ case MODEM: break; case REXMT: break; case INIT: xbcb = 0xa0; xfcs0 = 0x8f; xfcs1 = 0xcf; ackseq = 0x70; error = xmtctl(ENQ,NULL,ifp); break; case SENDBLK: error = xmtdata(ifp,bsc); bsc->bscp_state = NULL; break; } return(error);}bsc_input( m0 , dst) struct mbuf *m0; struct sockaddr_bsc *dst;{ register struct bsc_ifaddr *bia; register struct ifnet *ifp; struct bscpcb *bsc; struct socket *so; extern short state; int s; int error; struct sockaddr_bsc *sin; int saveaffinity; saveaffinity = switch_affinity(boot_cpu_mask); m_dvr = m0; rcvs = rec(); switch(state){ case REXMT: break; case INIT: switch( rcvs ){ case R_ACK: m_free(m0); s = splimp(); state = SENDBLK; bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; soisconnected(so); splx(s); bsc->b_rexmt = 0; break; default: m_free(m0); break; } break; case SENDBLKLAST: switch(rcvs){ case R_ACK: /* If last block is received on IBM side, then send * an eot message and wakeup the socket. */ m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } splx(s); ct1 = 0; nakctr = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); error = xmtctl(EOT,NULL,ifp); /* SENDACK0 is a transition state so get the * ack sequence set up in case we get to bid for the * line. */ ackseq = X70; state = SENDACK0; break; case R_RVI: /* We treat the RVI as an ACK plus line turn around * request. Therefore we process the RVI exactly like * and ack. We don't need to do anything special for * the RVI case. We don't even need to tell the * uper layers that an RVI character came in * because we are on the last block and * expect the other side to do a line bid anyway. */ m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); sin = &bsc->bscp_laddr; so = bsc->bscp_socket; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } splx(s); ct1 = 0; nakctr = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); error = xmtctl(EOT,NULL,ifp); ackseq = X70; state = SENDACK0; break; case R_SEQ: m_free(m0); ct1 = 0; s = splimp(); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; splx(s); ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } error = xmtdata(ifp, bsc); state = SENDBLKLAST; break; case R_NAK: /* May need some trap here that lets you receive only * x NAKs for the same block. */ m_free(m0); nakctr++; seqst = R_NAK; ct1 = 0; if (ackseq == X70) ackseq = 0x61; else ackseq = X70; bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } if (nakctr >= SEND_BLK_RETRY){ bsc->b_rexmt = nakctr + 1; so->so_error = ECONNABORTED; wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); break; } error = xmtdata(ifp, bsc); state = SENDBLKLAST; break; default: ++ct1; if(ct1 >= 6){ bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = ENETDOWN; break; }else{ m_free(m0); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } error = xmtctl(ENQ,NULL,ifp); state = SENDBLKLAST; } break; } break; case SENDBLK: switch(rcvs){ case R_ACK: m_free(m0); bsc = bsc_pcblookup(&bsb); /* It takes a while for the application layer * to generate another block so we need to * distinguish this state in order to send TTDs. */ bsc->bscp_state = R_ACK; bsc->b_rexmt = 0; bsc->b_timer = 0; s = splimp(); ct1 = 0; nakctr = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); so = bsc->bscp_socket; wakeup((caddr_t)&so->so_timeo); splx(s); sbdrop(&so->so_snd, so->so_snd.sb_cc); break; case R_RVI: /* * Note the wakeup situation here. We get an RVI then send * an EOT. Then we wakeup the send which falls to the * receive outofband routine which sleeps. In the meantime * we put the RVI in the outofband location in the socket * queue. When data eventually comes in, we wakeup the socket * The socket sees the RVI character and immediately goes to * read what is in the receive queue. */ m_free(m0); ct1 = 0; s = splimp(); bsc = bsc_pcblookup(&bsb); sin = &bsc->bscp_laddr; splx(s); so = bsc->bscp_socket; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); error = xmtctl(EOT,NULL,ifp); bsc_pulloutofband(bsc); ackseq = X70; state = SENDACK; break; case R_NAK: m_free(m0); nakctr++; seqst = R_NAK; ct1 = 0; /* if (ackseq == X70) * ackseq = 0x61; * else * ackseq = X70; */ bsc = bsc_pcblookup(&bsb); sin = &bsc->bscp_laddr; so = bsc->bscp_socket; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } /* You may want to send an EOT message here */ if (nakctr >= SEND_BLK_RETRY){ bsc->b_rexmt = nakctr + 1; so->so_error = ECONNABORTED; wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); break; } /* We are sending a TTD from the timers. Just let * the timers continue to do this. */ if (bsc->bscp_state == R_ACK) break; error = xmtdata(ifp, bsc); state = SENDBLK; break; case R_SEQ: m_free(m0); ct1 = 0; s = splimp(); bsc = bsc_pcblookup(&bsb); sin = &bsc->bscp_laddr; so = bsc->bscp_socket; splx(s); ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } error = xmtdata(ifp, bsc); state = SENDBLK; break; default: ++ct1; if(ct1 >= 6){ bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = ENETDOWN; break; }else{ m_free(m0); bsc = bsc_pcblookup(&bsb); sin = &bsc->bscp_laddr; so = bsc->bscp_socket; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ wakeup((caddr_t)&so->so_timeo); sbdrop(&so->so_snd, so->so_snd.sb_cc); so->so_error = EADDRNOTAVAIL; break; } error = xmtctl(ENQ,NULL,ifp); state = SENDBLK; } break; } break; case SENDACK0: switch(rcvs){ case ENQ: m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; bsc_pulloutofband(bsc); splx(s); ackseq = X70; error = xmtack(bsc); ct1 = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); state = SENDACK; break; case R_ACK: /* Let the timers keep the line alive. If * the timers kick in to do a line bid that * means that the other side doesn't want to * to send a file so we go to SENDBLK state. */ m_free(m0); s = splimp(); ct1 = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; wakeup((caddr_t)&so->so_timeo); splx(s); break; default: ++ct1; if(ct1 >= 6){ m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); splx(s); so = bsc->bscp_socket; so->so_error = ENETDOWN; bsc->b_timer = 0; wakeup((caddr_t)&so->so_timeo); exitval = ERRORS; } break; } break; case SENDACK: switch(rcvs){ case ENQ: m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); splx(s); bsc->b_rexmt++; so = bsc->bscp_socket; error = xmtack(bsc); if (error && (bsc->b_rexmt >= SEND_BLK_RETRY)){ bsc->b_rexmt = 0; so->so_error = ECONNABORTED; wakeup((caddr_t)&so->so_timeo); break; } ct1 = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); state = SENDACK; break; case R_OKBLK: m_freem(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; bsc->b_rexmt = 0; splx(s); if (ackseq == X70) ackseq = 0x61; else ackseq = X70; /* An error in sending here means a message didn't get * out. The other side must send ENQ in response so * let case ENQ handle the retransmit. */ error = xmtack(bsc); sbappend(&so->so_rcv, m_up); wakeup((caddr_t)&so->so_timeo); break; case R_ERBLK: m_freem(m0); m_freem(m_up); ct1 = 0; bsc = bsc_pcblookup(&bsb); bsc->b_rexmt++; so = bsc->bscp_socket; if (bsc->b_rexmt >= SEND_BLK_RETRY){ so->so_error = ECONNABORTED; bsc->b_rexmt = 0; wakeup((caddr_t)&so->so_timeo); break; } sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ so->so_error = EADDRNOTAVAIL; bsc->b_rexmt = 0; wakeup((caddr_t)&so->so_timeo); break; } error = xmtctl(NAK,NULL,ifp); if (error) bsc->b_rexmt--; state = SENDACK; break; case R_NAK: m_freem(m0); ct1 = 0; seqst = R_NAK; bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ so->so_error = EADDRNOTAVAIL; bsc->b_rexmt = 0; wakeup((caddr_t)&so->so_timeo); break; } error = xmtctl(DLE,X70,ifp); state = SENDACK; break; case EOT: m_free(m0); s = splimp(); bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; bsc_pulloutofband(bsc); splx(s); ct1 = 0; seqst = R_ACK; xbcb = 0x80|xseq; incmod(xseq,16); state = SENDACK0; /* SENDACK0 is a transition state so get the * ack sequence set up in case we get to bid for the * line. */ ackseq = X70; wakeup((caddr_t)&so->so_timeo); break; default: ++ct1; m_freem(m0); if(ct1 >= 6){ bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; so->so_error = ENETDOWN; bsc->b_rexmt = 0; wakeup((caddr_t)&so->so_timeo); break; }else{ bsc = bsc_pcblookup(&bsb); so = bsc->bscp_socket; sin = &bsc->bscp_laddr; ifp = (struct ifnet *)bsc_ifpfinder( sin ); if (ifp == 0){ so->so_error = EADDRNOTAVAIL; bsc->b_rexmt = 0; wakeup((caddr_t)&so->so_timeo); break; } error = xmtctl(NAK,NULL,ifp); state = SENDACK; } break; } break; }}/* Xmtdata prepares data for transmission to the protocol. When we get * the data at this level, there are a few flags in the data indicating * transparent/nontransparent and eof/eobuffer. The 0th location in the * first mbuf of data indicates transparent communication if its value is * 1. We note the value here and then delete it from the buffer so it * won't be transmitted as data. The last location in the last mbuf we * get tells us if this is the last buffer in the file or not. Again, * we see what the value is, take the proper action, and then delete so it * won't be transmitted as data. */xmtdata( ifp, bsc) struct ifnet *ifp; struct bscpcb *bsc;{ struct socket *so; struct sockaddr_bsc *dst; int i = 0; int j = 0; char c; struct mbuf *m, *mp, *m_head, *m_new; int len, off, error; int d_flag = 0; struct bsc_data *bm, *bmtmp; int saveaffinity;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -