|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)tcp_usrreq.c 7.15 (Berkeley) 6/28/90
21: */
22:
23: #include "param.h"
24: #include "systm.h"
25: #include "malloc.h"
26: #include "mbuf.h"
27: #include "socket.h"
28: #include "socketvar.h"
29: #include "protosw.h"
30: #include "errno.h"
31: #include "stat.h"
32:
33: #include "../net/if.h"
34: #include "../net/route.h"
35:
36: #include "in.h"
37: #include "in_systm.h"
38: #include "ip.h"
39: #include "in_pcb.h"
40: #include "ip_var.h"
41: #include "tcp.h"
42: #include "tcp_fsm.h"
43: #include "tcp_seq.h"
44: #include "tcp_timer.h"
45: #include "tcp_var.h"
46: #include "tcpip.h"
47: #include "tcp_debug.h"
48:
49: /*
50: * TCP protocol interface to socket abstraction.
51: */
52: extern char *tcpstates[];
53: struct tcpcb *tcp_newtcpcb();
54:
55: /*
56: * Process a TCP user request for TCP tb. If this is a send request
57: * then m is the mbuf chain of send data. If this is a timer expiration
58: * (called from the software clock routine), then timertype tells which timer.
59: */
60: /*ARGSUSED*/
61: tcp_usrreq(so, req, m, nam, control)
62: struct socket *so;
63: int req;
64: struct mbuf *m, *nam, *control;
65: {
66: register struct inpcb *inp;
67: register struct tcpcb *tp;
68: int s;
69: int error = 0;
70: int ostate;
71:
72: if (req == PRU_CONTROL)
73: return (in_control(so, (int)m, (caddr_t)nam,
74: (struct ifnet *)control));
75: if (control && control->m_len) {
76: m_freem(control);
77: if (m)
78: m_freem(m);
79: return (EINVAL);
80: }
81:
82: s = splnet();
83: inp = sotoinpcb(so);
84: /*
85: * When a TCP is attached to a socket, then there will be
86: * a (struct inpcb) pointed at by the socket, and this
87: * structure will point at a subsidary (struct tcpcb).
88: */
89: if (inp == 0 && req != PRU_ATTACH) {
90: splx(s);
91: return (EINVAL); /* XXX */
92: }
93: if (inp) {
94: tp = intotcpcb(inp);
95: /* WHAT IF TP IS 0? */
96: #ifdef KPROF
97: tcp_acounts[tp->t_state][req]++;
98: #endif
99: ostate = tp->t_state;
100: } else
101: ostate = 0;
102: switch (req) {
103:
104: /*
105: * TCP attaches to socket via PRU_ATTACH, reserving space,
106: * and an internet control block.
107: */
108: case PRU_ATTACH:
109: if (inp) {
110: error = EISCONN;
111: break;
112: }
113: error = tcp_attach(so);
114: if (error)
115: break;
116: if ((so->so_options & SO_LINGER) && so->so_linger == 0)
117: so->so_linger = TCP_LINGERTIME;
118: tp = sototcpcb(so);
119: break;
120:
121: /*
122: * PRU_DETACH detaches the TCP protocol from the socket.
123: * If the protocol state is non-embryonic, then can't
124: * do this directly: have to initiate a PRU_DISCONNECT,
125: * which may finish later; embryonic TCB's can just
126: * be discarded here.
127: */
128: case PRU_DETACH:
129: if (tp->t_state > TCPS_LISTEN)
130: tp = tcp_disconnect(tp);
131: else
132: tp = tcp_close(tp);
133: break;
134:
135: /*
136: * Give the socket an address.
137: */
138: case PRU_BIND:
139: error = in_pcbbind(inp, nam);
140: if (error)
141: break;
142: break;
143:
144: /*
145: * Prepare to accept connections.
146: */
147: case PRU_LISTEN:
148: if (inp->inp_lport == 0)
149: error = in_pcbbind(inp, (struct mbuf *)0);
150: if (error == 0)
151: tp->t_state = TCPS_LISTEN;
152: break;
153:
154: /*
155: * Initiate connection to peer.
156: * Create a template for use in transmissions on this connection.
157: * Enter SYN_SENT state, and mark socket as connecting.
158: * Start keep-alive timer, and seed output sequence space.
159: * Send initial segment on connection.
160: */
161: case PRU_CONNECT:
162: if (inp->inp_lport == 0) {
163: error = in_pcbbind(inp, (struct mbuf *)0);
164: if (error)
165: break;
166: }
167: error = in_pcbconnect(inp, nam);
168: if (error)
169: break;
170: tp->t_template = tcp_template(tp);
171: if (tp->t_template == 0) {
172: in_pcbdisconnect(inp);
173: error = ENOBUFS;
174: break;
175: }
176: soisconnecting(so);
177: tcpstat.tcps_connattempt++;
178: tp->t_state = TCPS_SYN_SENT;
179: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
180: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
181: tcp_sendseqinit(tp);
182: error = tcp_output(tp);
183: break;
184:
185: /*
186: * Create a TCP connection between two sockets.
187: */
188: case PRU_CONNECT2:
189: error = EOPNOTSUPP;
190: break;
191:
192: /*
193: * Initiate disconnect from peer.
194: * If connection never passed embryonic stage, just drop;
195: * else if don't need to let data drain, then can just drop anyways,
196: * else have to begin TCP shutdown process: mark socket disconnecting,
197: * drain unread data, state switch to reflect user close, and
198: * send segment (e.g. FIN) to peer. Socket will be really disconnected
199: * when peer sends FIN and acks ours.
200: *
201: * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
202: */
203: case PRU_DISCONNECT:
204: tp = tcp_disconnect(tp);
205: break;
206:
207: /*
208: * Accept a connection. Essentially all the work is
209: * done at higher levels; just return the address
210: * of the peer, storing through addr.
211: */
212: case PRU_ACCEPT: {
213: struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
214:
215: nam->m_len = sizeof (struct sockaddr_in);
216: sin->sin_family = AF_INET;
217: sin->sin_len = sizeof(*sin);
218: sin->sin_port = inp->inp_fport;
219: sin->sin_addr = inp->inp_faddr;
220: break;
221: }
222:
223: /*
224: * Mark the connection as being incapable of further output.
225: */
226: case PRU_SHUTDOWN:
227: socantsendmore(so);
228: tp = tcp_usrclosed(tp);
229: if (tp)
230: error = tcp_output(tp);
231: break;
232:
233: /*
234: * After a receive, possibly send window update to peer.
235: */
236: case PRU_RCVD:
237: (void) tcp_output(tp);
238: break;
239:
240: /*
241: * Do a send by putting data in output queue and updating urgent
242: * marker if URG set. Possibly send more data.
243: */
244: case PRU_SEND:
245: sbappend(&so->so_snd, m);
246: error = tcp_output(tp);
247: break;
248:
249: /*
250: * Abort the TCP.
251: */
252: case PRU_ABORT:
253: tp = tcp_drop(tp, ECONNABORTED);
254: break;
255:
256: case PRU_SENSE:
257: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
258: (void) splx(s);
259: return (0);
260:
261: case PRU_RCVOOB:
262: if ((so->so_oobmark == 0 &&
263: (so->so_state & SS_RCVATMARK) == 0) ||
264: so->so_options & SO_OOBINLINE ||
265: tp->t_oobflags & TCPOOB_HADDATA) {
266: error = EINVAL;
267: break;
268: }
269: if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
270: error = EWOULDBLOCK;
271: break;
272: }
273: m->m_len = 1;
274: *mtod(m, caddr_t) = tp->t_iobc;
275: if (((int)nam & MSG_PEEK) == 0)
276: tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
277: break;
278:
279: case PRU_SENDOOB:
280: if (sbspace(&so->so_snd) < -512) {
281: m_freem(m);
282: error = ENOBUFS;
283: break;
284: }
285: /*
286: * According to RFC961 (Assigned Protocols),
287: * the urgent pointer points to the last octet
288: * of urgent data. We continue, however,
289: * to consider it to indicate the first octet
290: * of data past the urgent section.
291: * Otherwise, snd_up should be one lower.
292: */
293: sbappend(&so->so_snd, m);
294: tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
295: tp->t_force = 1;
296: error = tcp_output(tp);
297: tp->t_force = 0;
298: break;
299:
300: case PRU_SOCKADDR:
301: in_setsockaddr(inp, nam);
302: break;
303:
304: case PRU_PEERADDR:
305: in_setpeeraddr(inp, nam);
306: break;
307:
308: /*
309: * TCP slow timer went off; going through this
310: * routine for tracing's sake.
311: */
312: case PRU_SLOWTIMO:
313: tp = tcp_timers(tp, (int)nam);
314: req |= (int)nam << 8; /* for debug's sake */
315: break;
316:
317: default:
318: panic("tcp_usrreq");
319: }
320: if (tp && (so->so_options & SO_DEBUG))
321: tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
322: splx(s);
323: return (error);
324: }
325:
326: tcp_ctloutput(op, so, level, optname, mp)
327: int op;
328: struct socket *so;
329: int level, optname;
330: struct mbuf **mp;
331: {
332: int error = 0;
333: struct inpcb *inp = sotoinpcb(so);
334: register struct tcpcb *tp = intotcpcb(inp);
335: register struct mbuf *m;
336:
337: if (level != IPPROTO_TCP)
338: return (ip_ctloutput(op, so, level, optname, mp));
339:
340: switch (op) {
341:
342: case PRCO_SETOPT:
343: m = *mp;
344: switch (optname) {
345:
346: case TCP_NODELAY:
347: if (m == NULL || m->m_len < sizeof (int))
348: error = EINVAL;
349: else if (*mtod(m, int *))
350: tp->t_flags |= TF_NODELAY;
351: else
352: tp->t_flags &= ~TF_NODELAY;
353: break;
354:
355: case TCP_MAXSEG: /* not yet */
356: default:
357: error = EINVAL;
358: break;
359: }
360: if (m)
361: (void) m_free(m);
362: break;
363:
364: case PRCO_GETOPT:
365: *mp = m = m_get(M_WAIT, MT_SOOPTS);
366: m->m_len = sizeof(int);
367:
368: switch (optname) {
369: case TCP_NODELAY:
370: *mtod(m, int *) = tp->t_flags & TF_NODELAY;
371: break;
372: case TCP_MAXSEG:
373: *mtod(m, int *) = tp->t_maxseg;
374: break;
375: default:
376: error = EINVAL;
377: break;
378: }
379: break;
380: }
381: return (error);
382: }
383:
384: u_long tcp_sendspace = 1024*4;
385: u_long tcp_recvspace = 1024*4;
386:
387: /*
388: * Attach TCP protocol to socket, allocating
389: * internet protocol control block, tcp control block,
390: * bufer space, and entering LISTEN state if to accept connections.
391: */
392: tcp_attach(so)
393: struct socket *so;
394: {
395: register struct tcpcb *tp;
396: struct inpcb *inp;
397: int error;
398:
399: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
400: error = soreserve(so, tcp_sendspace, tcp_recvspace);
401: if (error)
402: return (error);
403: }
404: error = in_pcballoc(so, &tcb);
405: if (error)
406: return (error);
407: inp = sotoinpcb(so);
408: tp = tcp_newtcpcb(inp);
409: if (tp == 0) {
410: int nofd = so->so_state & SS_NOFDREF; /* XXX */
411:
412: so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
413: in_pcbdetach(inp);
414: so->so_state |= nofd;
415: return (ENOBUFS);
416: }
417: tp->t_state = TCPS_CLOSED;
418: return (0);
419: }
420:
421: /*
422: * Initiate (or continue) disconnect.
423: * If embryonic state, just send reset (once).
424: * If in ``let data drain'' option and linger null, just drop.
425: * Otherwise (hard), mark socket disconnecting and drop
426: * current input data; switch states based on user close, and
427: * send segment to peer (with FIN).
428: */
429: struct tcpcb *
430: tcp_disconnect(tp)
431: register struct tcpcb *tp;
432: {
433: struct socket *so = tp->t_inpcb->inp_socket;
434:
435: if (tp->t_state < TCPS_ESTABLISHED)
436: tp = tcp_close(tp);
437: else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
438: tp = tcp_drop(tp, 0);
439: else {
440: soisdisconnecting(so);
441: sbflush(&so->so_rcv);
442: tp = tcp_usrclosed(tp);
443: if (tp)
444: (void) tcp_output(tp);
445: }
446: return (tp);
447: }
448:
449: /*
450: * User issued close, and wish to trail through shutdown states:
451: * if never received SYN, just forget it. If got a SYN from peer,
452: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
453: * If already got a FIN from peer, then almost done; go to LAST_ACK
454: * state. In all other cases, have already sent FIN to peer (e.g.
455: * after PRU_SHUTDOWN), and just have to play tedious game waiting
456: * for peer to send FIN or not respond to keep-alives, etc.
457: * We can let the user exit from the close as soon as the FIN is acked.
458: */
459: struct tcpcb *
460: tcp_usrclosed(tp)
461: register struct tcpcb *tp;
462: {
463:
464: switch (tp->t_state) {
465:
466: case TCPS_CLOSED:
467: case TCPS_LISTEN:
468: case TCPS_SYN_SENT:
469: tp->t_state = TCPS_CLOSED;
470: tp = tcp_close(tp);
471: break;
472:
473: case TCPS_SYN_RECEIVED:
474: case TCPS_ESTABLISHED:
475: tp->t_state = TCPS_FIN_WAIT_1;
476: break;
477:
478: case TCPS_CLOSE_WAIT:
479: tp->t_state = TCPS_LAST_ACK;
480: break;
481: }
482: if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
483: soisdisconnected(tp->t_inpcb->inp_socket);
484: return (tp);
485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.