xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5089)
1 /* tcp_usrreq.c 1.36 81/11/26 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../h/protosw.h"
9 #include "../net/in.h"
10 #include "../net/in_pcb.h"
11 #include "../net/in_systm.h"
12 #include "../net/if.h"
13 #include "../net/ip.h"
14 #include "../net/ip_var.h"
15 #include "../net/tcp.h"
16 #include "../net/tcp_fsm.h"
17 #include "../net/tcp_seq.h"
18 #include "../net/tcp_timer.h"
19 #include "../net/tcp_var.h"
20 #include "../net/tcpip.h"
21 #include "/usr/include/errno.h"
22 
23 struct	tcpcb *tcp_newtcpcb();
24 /*
25  * Process a TCP user request for tcp tb.  If this is a send request
26  * then m is the mbuf chain of send data.  If this is a timer expiration
27  * (called from the software clock routine), then timertype tells which timer.
28  */
29 tcp_usrreq(so, req, m, addr)
30 	struct socket *so;
31 	int req;
32 	struct mbuf *m;
33 	caddr_t addr;
34 {
35 	register struct inpcb *inp = sotoinpcb(so);
36 	register struct tcpcb *tp;
37 	int s = splnet();
38 	int error = 0;
39 	struct tcpiphdr ti;
40 COUNT(TCP_USRREQ);
41 
42 	/*
43 	 * Make sure attached.  If not,
44 	 * only PRU_ATTACH is valid.
45 	 */
46 	if (inp == 0 && req != PRU_ATTACH) {
47 		splx(s);
48 		return (EINVAL);
49 	}
50 	if (inp) {
51 		tp = intotcpcb(inp);
52 #ifdef KPROF
53 		tcp_acounts[tp->t_state][req]++;
54 #endif
55 	}
56 	switch (req) {
57 
58 	case PRU_ATTACH:
59 		if (inp) {
60 			error = EISCONN;
61 			break;
62 		}
63 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
64 		if (error)
65 			break;
66 		inp = (struct inpcb *)so->so_pcb;
67 		if (so->so_options & SO_ACCEPTCONN) {
68 			tp = tcp_newtcpcb(inp);
69 			if (tp == 0) {
70 				in_pcbfree(inp);
71 				error = ENOBUFS;
72 				break;
73 			}
74 			tp->t_state = TCPS_LISTEN;
75 		} else
76 			tp->t_state = TCPS_CLOSED;
77 		break;
78 
79 	case PRU_DETACH:
80 		break;
81 
82 	case PRU_CONNECT:
83 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
84 		if (error)
85 			break;
86 		tp = tcp_newtcpcb(inp);
87 		if (tp == 0) {
88 			inp->inp_faddr.s_addr = 0;
89 			error = ENOBUFS;
90 			break;
91 		}
92 		tp->t_inpcb = inp;
93 		inp->inp_ppcb = (caddr_t)tp;
94 		soisconnecting(so);
95 		tp->t_state = TCPS_SYN_SENT;
96 		tcp_output(tp);
97 		break;
98 
99 	case PRU_ACCEPT:
100 		soisconnected(so);
101 		break;
102 
103 	case PRU_DISCONNECT:
104 		if (tp->t_state < TCPS_ESTABLISHED)
105 			tcp_close(tp);
106 		else {
107 			soisdisconnecting(so);
108 			tcp_output(tp);
109 		}
110 		break;
111 
112 	case PRU_SHUTDOWN:
113 		socantsendmore(so);
114 		switch (tp->t_state) {
115 
116 		case TCPS_LISTEN:
117 		case TCPS_SYN_SENT:
118 			tp->t_state = TCPS_CLOSED;
119 			break;
120 
121 		case TCPS_SYN_RECEIVED:
122 		case TCPS_ESTABLISHED:
123 			tp->t_state = TCPS_FIN_WAIT_1;
124 			tcp_output(tp);
125 			break;
126 
127 		case TCPS_CLOSE_WAIT:
128 			tp->t_state = TCPS_LAST_ACK;
129 			tcp_output(tp);
130 			break;
131 		}
132 		break;
133 
134 	case PRU_RCVD:
135 		tcp_output(tp);
136 		break;
137 
138 	case PRU_SEND:
139 		sbappend(&so->so_snd, m);
140 /*
141 		if (tp->t_flags & TF_PUSH)
142 			tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
143  */
144 		if (tp->t_flags & TF_URG)
145 			tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1;
146 		tcp_output(tp);
147 		break;
148 
149 	case PRU_ABORT:
150 		tcp_drop(tp, ECONNABORTED);
151 		break;
152 
153 	case PRU_CONTROL:
154 		error = EOPNOTSUPP;
155 		break;
156 
157 	case PRU_SLOWTIMO:
158 		tcp_timers(tp, (int)addr);
159 		break;
160 
161 	default:
162 		panic("tcp_usrreq");
163 	}
164 	splx(s);
165 	return (error);
166 }
167