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