OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [netinet/] [tcp_usrreq.c] - Blame information for rev 773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 * Copyright (c) 1982, 1986, 1988, 1993
3
 *      The Regents of the University of California.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. All advertising materials mentioning features or use of this software
14
 *    must display the following acknowledgement:
15
 *      This product includes software developed by the University of
16
 *      California, Berkeley and its contributors.
17
 * 4. Neither the name of the University nor the names of its contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
 * SUCH DAMAGE.
32
 *
33
 *      From: @(#)tcp_usrreq.c  8.2 (Berkeley) 1/3/94
34
 *      $Id: tcp_usrreq.c,v 1.2 2001-09-27 12:01:56 chris Exp $
35
 */
36
 
37
#include "opt_tcpdebug.h"
38
 
39
#include <sys/param.h>
40
#include <sys/queue.h>
41
#include <sys/systm.h>
42
#include <sys/kernel.h>
43
#include <sys/sysctl.h>
44
#include <sys/malloc.h>
45
#include <sys/mbuf.h>
46
#include <sys/socket.h>
47
#include <sys/socketvar.h>
48
#include <sys/protosw.h>
49
#include <sys/errno.h>
50
#include <sys/stat.h>
51
 
52
#include <net/if.h>
53
#include <net/route.h>
54
 
55
#include <netinet/in.h>
56
#include <netinet/in_systm.h>
57
#include <netinet/ip.h>
58
#include <netinet/in_pcb.h>
59
#include <netinet/in_var.h>
60
#include <netinet/ip_var.h>
61
#include <netinet/tcp.h>
62
#include <netinet/tcp_fsm.h>
63
#include <netinet/tcp_seq.h>
64
#include <netinet/tcp_timer.h>
65
#include <netinet/tcp_var.h>
66
#include <netinet/tcpip.h>
67
#ifdef TCPDEBUG
68
#include <netinet/tcp_debug.h>
69
#endif
70
 
71
/*
72
 * TCP protocol interface to socket abstraction.
73
 */
74
extern  char *tcpstates[];
75
 
76
static int      tcp_attach __P((struct socket *));
77
static int      tcp_connect __P((struct tcpcb *, struct mbuf *));
78
static struct tcpcb *
79
                tcp_disconnect __P((struct tcpcb *));
80
static struct tcpcb *
81
                tcp_usrclosed __P((struct tcpcb *));
82
 
83
#ifdef TCPDEBUG
84
#define TCPDEBUG0       int ostate
85
#define TCPDEBUG1()     ostate = tp ? tp->t_state : 0
86
#define TCPDEBUG2(req)  if (tp && (so->so_options & SO_DEBUG)) \
87
                                tcp_trace(TA_USER, ostate, tp, 0, req)
88
#else
89
#define TCPDEBUG0
90
#define TCPDEBUG1()
91
#define TCPDEBUG2(req)
92
#endif
93
 
94
/*
95
 * TCP attaches to socket via pru_attach(), reserving space,
96
 * and an internet control block.
97
 */
98
static int
99
tcp_usr_attach(struct socket *so, int proto)
100
{
101
        int s = splnet();
102
        int error;
103
        struct inpcb *inp = sotoinpcb(so);
104
        struct tcpcb *tp = 0;
105
        TCPDEBUG0;
106
 
107
        TCPDEBUG1();
108
        if (inp) {
109
                error = EISCONN;
110
                goto out;
111
        }
112
 
113
        error = tcp_attach(so);
114
        if (error)
115
                goto out;
116
 
117
        if ((so->so_options & SO_LINGER) && so->so_linger == 0)
118
                so->so_linger = TCP_LINGERTIME * hz;
119
        tp = sototcpcb(so);
120
out:
121
        TCPDEBUG2(PRU_ATTACH);
122
        splx(s);
123
        return error;
124
}
125
 
126
/*
127
 * pru_detach() detaches the TCP protocol from the socket.
128
 * If the protocol state is non-embryonic, then can't
129
 * do this directly: have to initiate a pru_disconnect(),
130
 * which may finish later; embryonic TCB's can just
131
 * be discarded here.
132
 */
133
static int
134
tcp_usr_detach(struct socket *so)
135
{
136
        int s = splnet();
137
        int error = 0;
138
        struct inpcb *inp = sotoinpcb(so);
139
        struct tcpcb *tp;
140
        TCPDEBUG0;
141
 
142
        if (inp == 0) {
143
                splx(s);
144
                return EINVAL;  /* XXX */
145
        }
146
        tp = intotcpcb(inp);
147
        TCPDEBUG1();
148
        if (tp->t_state > TCPS_LISTEN)
149
                tp = tcp_disconnect(tp);
150
        else
151
                tp = tcp_close(tp);
152
 
153
        TCPDEBUG2(PRU_DETACH);
154
        splx(s);
155
        return error;
156
}
157
 
158
#define COMMON_START()  TCPDEBUG0; \
159
                        do { \
160
                                     if (inp == 0) { \
161
                                             splx(s); \
162
                                             return EINVAL; \
163
                                     } \
164
                                     tp = intotcpcb(inp); \
165
                                     TCPDEBUG1(); \
166
                     } while(0)
167
 
168
#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out
169
 
170
 
171
/*
172
 * Give the socket an address.
173
 */
174
static int
175
tcp_usr_bind(struct socket *so, struct mbuf *nam)
176
{
177
        int s = splnet();
178
        int error = 0;
179
        struct inpcb *inp = sotoinpcb(so);
180
        struct tcpcb *tp;
181
        struct sockaddr_in *sinp;
182
 
183
        COMMON_START();
184
 
185
        /*
186
         * Must check for multicast addresses and disallow binding
187
         * to them.
188
         */
189
        sinp = mtod(nam, struct sockaddr_in *);
190
        if (sinp->sin_family == AF_INET &&
191
            IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
192
                error = EAFNOSUPPORT;
193
                goto out;
194
        }
195
        error = in_pcbbind(inp, nam);
196
        if (error)
197
                goto out;
198
        COMMON_END(PRU_BIND);
199
 
200
}
201
 
202
/*
203
 * Prepare to accept connections.
204
 */
205
static int
206
tcp_usr_listen(struct socket *so)
207
{
208
        int s = splnet();
209
        int error = 0;
210
        struct inpcb *inp = sotoinpcb(so);
211
        struct tcpcb *tp;
212
 
213
        COMMON_START();
214
        if (inp->inp_lport == 0)
215
                error = in_pcbbind(inp, NULL);
216
        if (error == 0)
217
                tp->t_state = TCPS_LISTEN;
218
        COMMON_END(PRU_LISTEN);
219
}
220
 
221
/*
222
 * Initiate connection to peer.
223
 * Create a template for use in transmissions on this connection.
224
 * Enter SYN_SENT state, and mark socket as connecting.
225
 * Start keep-alive timer, and seed output sequence space.
226
 * Send initial segment on connection.
227
 */
228
static int
229
tcp_usr_connect(struct socket *so, struct mbuf *nam)
230
{
231
        int s = splnet();
232
        int error = 0;
233
        struct inpcb *inp = sotoinpcb(so);
234
        struct tcpcb *tp;
235
        struct sockaddr_in *sinp;
236
 
237
        COMMON_START();
238
 
239
        /*
240
         * Must disallow TCP ``connections'' to multicast addresses.
241
         */
242
        sinp = mtod(nam, struct sockaddr_in *);
243
        if (sinp->sin_family == AF_INET
244
            && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
245
                error = EAFNOSUPPORT;
246
                goto out;
247
        }
248
 
249
        if ((error = tcp_connect(tp, nam)) != 0)
250
                goto out;
251
        error = tcp_output(tp);
252
        COMMON_END(PRU_CONNECT);
253
}
254
 
255
/*
256
 * Initiate disconnect from peer.
257
 * If connection never passed embryonic stage, just drop;
258
 * else if don't need to let data drain, then can just drop anyways,
259
 * else have to begin TCP shutdown process: mark socket disconnecting,
260
 * drain unread data, state switch to reflect user close, and
261
 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
262
 * when peer sends FIN and acks ours.
263
 *
264
 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
265
 */
266
static int
267
tcp_usr_disconnect(struct socket *so)
268
{
269
        int s = splnet();
270
        int error = 0;
271
        struct inpcb *inp = sotoinpcb(so);
272
        struct tcpcb *tp;
273
 
274
        COMMON_START();
275
        tp = tcp_disconnect(tp);
276
        COMMON_END(PRU_DISCONNECT);
277
}
278
 
279
/*
280
 * Accept a connection.  Essentially all the work is
281
 * done at higher levels; just return the address
282
 * of the peer, storing through addr.
283
 */
284
static int
285
tcp_usr_accept(struct socket *so, struct mbuf *nam)
286
{
287
        int s = splnet();
288
        int error = 0;
289
        struct inpcb *inp = sotoinpcb(so);
290
        struct tcpcb *tp;
291
 
292
        COMMON_START();
293
        in_setpeeraddr(inp, nam);
294
        COMMON_END(PRU_ACCEPT);
295
}
296
 
297
/*
298
 * Mark the connection as being incapable of further output.
299
 */
300
static int
301
tcp_usr_shutdown(struct socket *so)
302
{
303
        int s = splnet();
304
        int error = 0;
305
        struct inpcb *inp = sotoinpcb(so);
306
        struct tcpcb *tp;
307
 
308
        COMMON_START();
309
        socantsendmore(so);
310
        tp = tcp_usrclosed(tp);
311
        if (tp)
312
                error = tcp_output(tp);
313
        COMMON_END(PRU_SHUTDOWN);
314
}
315
 
316
/*
317
 * After a receive, possibly send window update to peer.
318
 */
319
static int
320
tcp_usr_rcvd(struct socket *so, int flags)
321
{
322
        int s = splnet();
323
        int error = 0;
324
        struct inpcb *inp = sotoinpcb(so);
325
        struct tcpcb *tp;
326
 
327
        COMMON_START();
328
        tcp_output(tp);
329
        COMMON_END(PRU_RCVD);
330
}
331
 
332
/*
333
 * Do a send by putting data in output queue and updating urgent
334
 * marker if URG set.  Possibly send more data.
335
 */
336
static int
337
tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
338
             struct mbuf *control)
339
{
340
        int s = splnet();
341
        int error = 0;
342
        struct inpcb *inp = sotoinpcb(so);
343
        struct tcpcb *tp;
344
 
345
        COMMON_START();
346
        if (control && control->m_len) {
347
                m_freem(control); /* XXX shouldn't caller do this??? */
348
                if (m)
349
                        m_freem(m);
350
                error = EINVAL;
351
                goto out;
352
        }
353
 
354
        if(!(flags & PRUS_OOB)) {
355
                sbappend(&so->so_snd, m);
356
                if (nam && tp->t_state < TCPS_SYN_SENT) {
357
                        /*
358
                         * Do implied connect if not yet connected,
359
                         * initialize window to default value, and
360
                         * initialize maxseg/maxopd using peer's cached
361
                         * MSS.
362
                         */
363
                        error = tcp_connect(tp, nam);
364
                        if (error)
365
                                goto out;
366
                        tp->snd_wnd = TTCP_CLIENT_SND_WND;
367
                        tcp_mss(tp, -1);
368
                }
369
 
370
                if (flags & PRUS_EOF) {
371
                        /*
372
                         * Close the send side of the connection after
373
                         * the data is sent.
374
                         */
375
                        socantsendmore(so);
376
                        tp = tcp_usrclosed(tp);
377
                }
378
                if (tp != NULL)
379
                        error = tcp_output(tp);
380
        } else {
381
                if (sbspace(&so->so_snd) < -512) {
382
                        m_freem(m);
383
                        error = ENOBUFS;
384
                        goto out;
385
                }
386
                /*
387
                 * According to RFC961 (Assigned Protocols),
388
                 * the urgent pointer points to the last octet
389
                 * of urgent data.  We continue, however,
390
                 * to consider it to indicate the first octet
391
                 * of data past the urgent section.
392
                 * Otherwise, snd_up should be one lower.
393
                 */
394
                sbappend(&so->so_snd, m);
395
                if (nam && tp->t_state < TCPS_SYN_SENT) {
396
                        /*
397
                         * Do implied connect if not yet connected,
398
                         * initialize window to default value, and
399
                         * initialize maxseg/maxopd using peer's cached
400
                         * MSS.
401
                         */
402
                        error = tcp_connect(tp, nam);
403
                        if (error)
404
                                goto out;
405
                        tp->snd_wnd = TTCP_CLIENT_SND_WND;
406
                        tcp_mss(tp, -1);
407
                }
408
                tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
409
                tp->t_force = 1;
410
                error = tcp_output(tp);
411
                tp->t_force = 0;
412
        }
413
        COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB :
414
                   ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
415
}
416
 
417
/*
418
 * Abort the TCP.
419
 */
420
static int
421
tcp_usr_abort(struct socket *so)
422
{
423
        int s = splnet();
424
        int error = 0;
425
        struct inpcb *inp = sotoinpcb(so);
426
        struct tcpcb *tp;
427
 
428
        COMMON_START();
429
        tp = tcp_drop(tp, ECONNABORTED);
430
        COMMON_END(PRU_ABORT);
431
}
432
 
433
/*
434
 * Fill in st_bklsize for fstat() operations on a socket.
435
 */
436
static int
437
tcp_usr_sense(struct socket *so, struct stat *sb)
438
{
439
        int s = splnet();
440
 
441
        sb->st_blksize = so->so_snd.sb_hiwat;
442
        splx(s);
443
        return 0;
444
}
445
 
446
/*
447
 * Receive out-of-band data.
448
 */
449
static int
450
tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
451
{
452
        int s = splnet();
453
        int error = 0;
454
        struct inpcb *inp = sotoinpcb(so);
455
        struct tcpcb *tp;
456
 
457
        COMMON_START();
458
        if ((so->so_oobmark == 0 &&
459
             (so->so_state & SS_RCVATMARK) == 0) ||
460
            so->so_options & SO_OOBINLINE ||
461
            tp->t_oobflags & TCPOOB_HADDATA) {
462
                error = EINVAL;
463
                goto out;
464
        }
465
        if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
466
                error = EWOULDBLOCK;
467
                goto out;
468
        }
469
        m->m_len = 1;
470
        *mtod(m, caddr_t) = tp->t_iobc;
471
        if ((flags & MSG_PEEK) == 0)
472
                tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
473
        COMMON_END(PRU_RCVOOB);
474
}
475
 
476
static int
477
tcp_usr_sockaddr(struct socket *so, struct mbuf *nam)
478
{
479
        int s = splnet();
480
        int error = 0;
481
        struct inpcb *inp = sotoinpcb(so);
482
        struct tcpcb *tp;
483
 
484
        COMMON_START();
485
        in_setsockaddr(inp, nam);
486
        COMMON_END(PRU_SOCKADDR);
487
}
488
 
489
static int
490
tcp_usr_peeraddr(struct socket *so, struct mbuf *nam)
491
{
492
        int s = splnet();
493
        int error = 0;
494
        struct inpcb *inp = sotoinpcb(so);
495
        struct tcpcb *tp;
496
 
497
        COMMON_START();
498
        in_setpeeraddr(inp, nam);
499
        COMMON_END(PRU_PEERADDR);
500
}
501
 
502
/*
503
 * XXX - this should just be a call to in_control, but we need to get
504
 * the types worked out.
505
 */
506
static int
507
tcp_usr_control(struct socket *so, int cmd, caddr_t arg, struct ifnet *ifp)
508
{
509
        return in_control(so, cmd, arg, ifp);
510
}
511
 
512
/* xxx - should be const */
513
struct pr_usrreqs tcp_usrreqs = {
514
        tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
515
        tcp_usr_connect, pru_connect2_notsupp, tcp_usr_control, tcp_usr_detach,
516
        tcp_usr_disconnect, tcp_usr_listen, tcp_usr_peeraddr, tcp_usr_rcvd,
517
        tcp_usr_rcvoob, tcp_usr_send, tcp_usr_sense, tcp_usr_shutdown,
518
        tcp_usr_sockaddr
519
};
520
 
521
/*
522
 * Common subroutine to open a TCP connection to remote host specified
523
 * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
524
 * port number if needed.  Call in_pcbladdr to do the routing and to choose
525
 * a local host address (interface).  If there is an existing incarnation
526
 * of the same connection in TIME-WAIT state and if the remote host was
527
 * sending CC options and if the connection duration was < MSL, then
528
 * truncate the previous TIME-WAIT state and proceed.
529
 * Initialize connection parameters and enter SYN-SENT state.
530
 */
531
static int
532
tcp_connect(tp, nam)
533
        register struct tcpcb *tp;
534
        struct mbuf *nam;
535
{
536
        struct inpcb *inp = tp->t_inpcb, *oinp;
537
        struct socket *so = inp->inp_socket;
538
        struct tcpcb *otp;
539
        struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
540
        struct sockaddr_in *ifaddr;
541
        int error;
542
        struct rmxp_tao *taop;
543
        struct rmxp_tao tao_noncached;
544
 
545
        if (inp->inp_lport == 0) {
546
                error = in_pcbbind(inp, NULL);
547
                if (error)
548
                        return error;
549
        }
550
 
551
        /*
552
         * Cannot simply call in_pcbconnect, because there might be an
553
         * earlier incarnation of this same connection still in
554
         * TIME_WAIT state, creating an ADDRINUSE error.
555
         */
556
        error = in_pcbladdr(inp, nam, &ifaddr);
557
        if (error)
558
                return error;
559
        oinp = in_pcblookuphash(inp->inp_pcbinfo,
560
            sin->sin_addr, sin->sin_port,
561
            inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
562
                                                : ifaddr->sin_addr,
563
            inp->inp_lport,  0);
564
        if (oinp) {
565
                if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
566
                otp->t_state == TCPS_TIME_WAIT &&
567
                    otp->t_duration < TCPTV_MSL &&
568
                    (otp->t_flags & TF_RCVD_CC))
569
                        otp = tcp_close(otp);
570
                else
571
                        return EADDRINUSE;
572
        }
573
        if (inp->inp_laddr.s_addr == INADDR_ANY)
574
                inp->inp_laddr = ifaddr->sin_addr;
575
        inp->inp_faddr = sin->sin_addr;
576
        inp->inp_fport = sin->sin_port;
577
        in_pcbrehash(inp);
578
 
579
        tp->t_template = tcp_template(tp);
580
        if (tp->t_template == 0) {
581
                in_pcbdisconnect(inp);
582
                return ENOBUFS;
583
        }
584
 
585
        /* Compute window scaling to request.  */
586
        while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
587
            (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
588
                tp->request_r_scale++;
589
 
590
        soisconnecting(so);
591
        tcpstat.tcps_connattempt++;
592
        tp->t_state = TCPS_SYN_SENT;
593
        tp->t_timer[TCPT_KEEP] = tcp_keepinit;
594
        tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
595
        tcp_sendseqinit(tp);
596
 
597
        /*
598
         * Generate a CC value for this connection and
599
         * check whether CC or CCnew should be used.
600
         */
601
        if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
602
                taop = &tao_noncached;
603
                bzero(taop, sizeof(*taop));
604
        }
605
 
606
        tp->cc_send = CC_INC(tcp_ccgen);
607
        if (taop->tao_ccsent != 0 &&
608
            CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
609
                taop->tao_ccsent = tp->cc_send;
610
        } else {
611
                taop->tao_ccsent = 0;
612
                tp->t_flags |= TF_SENDCCNEW;
613
        }
614
 
615
        return 0;
616
}
617
 
618
int
619
tcp_ctloutput(op, so, level, optname, mp)
620
        int op;
621
        struct socket *so;
622
        int level, optname;
623
        struct mbuf **mp;
624
{
625
        int error = 0, s;
626
        struct inpcb *inp;
627
        register struct tcpcb *tp;
628
        register struct mbuf *m;
629
        register int i;
630
 
631
        s = splnet();
632
        inp = sotoinpcb(so);
633
        if (inp == NULL) {
634
                splx(s);
635
                if (op == PRCO_SETOPT && *mp)
636
                        (void) m_free(*mp);
637
                return (ECONNRESET);
638
        }
639
        if (level != IPPROTO_TCP) {
640
                error = ip_ctloutput(op, so, level, optname, mp);
641
                splx(s);
642
                return (error);
643
        }
644
        tp = intotcpcb(inp);
645
 
646
        switch (op) {
647
 
648
        case PRCO_SETOPT:
649
                m = *mp;
650
                switch (optname) {
651
 
652
                case TCP_NODELAY:
653
                        if (m == NULL || m->m_len < sizeof (int))
654
                                error = EINVAL;
655
                        else if (*mtod(m, int *))
656
                                tp->t_flags |= TF_NODELAY;
657
                        else
658
                                tp->t_flags &= ~TF_NODELAY;
659
                        break;
660
 
661
                case TCP_MAXSEG:
662
                        if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
663
                                tp->t_maxseg = i;
664
                        else
665
                                error = EINVAL;
666
                        break;
667
 
668
                case TCP_NOOPT:
669
                        if (m == NULL || m->m_len < sizeof (int))
670
                                error = EINVAL;
671
                        else if (*mtod(m, int *))
672
                                tp->t_flags |= TF_NOOPT;
673
                        else
674
                                tp->t_flags &= ~TF_NOOPT;
675
                        break;
676
 
677
                case TCP_NOPUSH:
678
                        if (m == NULL || m->m_len < sizeof (int))
679
                                error = EINVAL;
680
                        else if (*mtod(m, int *))
681
                                tp->t_flags |= TF_NOPUSH;
682
                        else
683
                                tp->t_flags &= ~TF_NOPUSH;
684
                        break;
685
 
686
                default:
687
                        error = ENOPROTOOPT;
688
                        break;
689
                }
690
                if (m)
691
                        (void) m_free(m);
692
                break;
693
 
694
        case PRCO_GETOPT:
695
                *mp = m = m_get(M_WAIT, MT_SOOPTS);
696
                m->m_len = sizeof(int);
697
 
698
                switch (optname) {
699
                case TCP_NODELAY:
700
                        *mtod(m, int *) = tp->t_flags & TF_NODELAY;
701
                        break;
702
                case TCP_MAXSEG:
703
                        *mtod(m, int *) = tp->t_maxseg;
704
                        break;
705
                case TCP_NOOPT:
706
                        *mtod(m, int *) = tp->t_flags & TF_NOOPT;
707
                        break;
708
                case TCP_NOPUSH:
709
                        *mtod(m, int *) = tp->t_flags & TF_NOPUSH;
710
                        break;
711
                default:
712
                        error = ENOPROTOOPT;
713
                        break;
714
                }
715
                break;
716
        }
717
        splx(s);
718
        return (error);
719
}
720
 
721
/*
722
 * tcp_sendspace and tcp_recvspace are the default send and receive window
723
 * sizes, respectively.  These are obsolescent (this information should
724
 * be set by the route).
725
 */
726
u_long  tcp_sendspace = 1024*16;
727
SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace,
728
        CTLFLAG_RW, &tcp_sendspace , 0, "");
729
u_long  tcp_recvspace = 1024*16;
730
SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace,
731
        CTLFLAG_RW, &tcp_recvspace , 0, "");
732
 
733
/*
734
 * Attach TCP protocol to socket, allocating
735
 * internet protocol control block, tcp control block,
736
 * bufer space, and entering LISTEN state if to accept connections.
737
 */
738
static int
739
tcp_attach(so)
740
        struct socket *so;
741
{
742
        register struct tcpcb *tp;
743
        struct inpcb *inp;
744
        int error;
745
 
746
        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
747
                error = soreserve(so, tcp_sendspace, tcp_recvspace);
748
                if (error)
749
                        return (error);
750
        }
751
        error = in_pcballoc(so, &tcbinfo);
752
        if (error)
753
                return (error);
754
        inp = sotoinpcb(so);
755
        tp = tcp_newtcpcb(inp);
756
        if (tp == 0) {
757
                int nofd = so->so_state & SS_NOFDREF;   /* XXX */
758
 
759
                so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
760
                in_pcbdetach(inp);
761
                so->so_state |= nofd;
762
                return (ENOBUFS);
763
        }
764
        tp->t_state = TCPS_CLOSED;
765
        return (0);
766
}
767
 
768
/*
769
 * Initiate (or continue) disconnect.
770
 * If embryonic state, just send reset (once).
771
 * If in ``let data drain'' option and linger null, just drop.
772
 * Otherwise (hard), mark socket disconnecting and drop
773
 * current input data; switch states based on user close, and
774
 * send segment to peer (with FIN).
775
 */
776
static struct tcpcb *
777
tcp_disconnect(tp)
778
        register struct tcpcb *tp;
779
{
780
        struct socket *so = tp->t_inpcb->inp_socket;
781
 
782
        if (tp->t_state < TCPS_ESTABLISHED)
783
                tp = tcp_close(tp);
784
        else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
785
                tp = tcp_drop(tp, 0);
786
        else {
787
                soisdisconnecting(so);
788
                sbflush(&so->so_rcv);
789
                tp = tcp_usrclosed(tp);
790
                if (tp)
791
                        (void) tcp_output(tp);
792
        }
793
        return (tp);
794
}
795
 
796
/*
797
 * User issued close, and wish to trail through shutdown states:
798
 * if never received SYN, just forget it.  If got a SYN from peer,
799
 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
800
 * If already got a FIN from peer, then almost done; go to LAST_ACK
801
 * state.  In all other cases, have already sent FIN to peer (e.g.
802
 * after PRU_SHUTDOWN), and just have to play tedious game waiting
803
 * for peer to send FIN or not respond to keep-alives, etc.
804
 * We can let the user exit from the close as soon as the FIN is acked.
805
 */
806
static struct tcpcb *
807
tcp_usrclosed(tp)
808
        register struct tcpcb *tp;
809
{
810
 
811
        switch (tp->t_state) {
812
 
813
        case TCPS_CLOSED:
814
        case TCPS_LISTEN:
815
                tp->t_state = TCPS_CLOSED;
816
                tp = tcp_close(tp);
817
                break;
818
 
819
        case TCPS_SYN_SENT:
820
        case TCPS_SYN_RECEIVED:
821
                tp->t_flags |= TF_NEEDFIN;
822
                break;
823
 
824
        case TCPS_ESTABLISHED:
825
                tp->t_state = TCPS_FIN_WAIT_1;
826
                break;
827
 
828
        case TCPS_CLOSE_WAIT:
829
                tp->t_state = TCPS_LAST_ACK;
830
                break;
831
        }
832
        if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
833
                soisdisconnected(tp->t_inpcb->inp_socket);
834
                /* To prevent the connection hanging in FIN_WAIT_2 forever. */
835
                if (tp->t_state == TCPS_FIN_WAIT_2)
836
                        tp->t_timer[TCPT_2MSL] = tcp_maxidle;
837
        }
838
        return (tp);
839
}
840
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.