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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet/] [tcp_usrreq.c] - Blame information for rev 631

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet/tcp_usrreq.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*
23
 * Copyright (c) 1982, 1986, 1988, 1993
24
 *      The Regents of the University of California.  All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. All advertising materials mentioning features or use of this software
35
 *    must display the following acknowledgement:
36
 *      This product includes software developed by the University of
37
 *      California, Berkeley and its contributors.
38
 * 4. Neither the name of the University nor the names of its contributors
39
 *    may be used to endorse or promote products derived from this software
40
 *    without specific prior written permission.
41
 *
42
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52
 * SUCH DAMAGE.
53
 *
54
 *      From: @(#)tcp_usrreq.c  8.2 (Berkeley) 1/3/94
55
 * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.51.2.9 2001/08/22 00:59:12 silby Exp $
56
 */
57
 
58
#include <sys/param.h>
59
#include <sys/mbuf.h>
60
#ifdef INET6
61
#include <sys/domain.h>
62
#endif /* INET6 */
63
#include <sys/socket.h>
64
#include <sys/socketvar.h>
65
#include <sys/protosw.h>
66
 
67
#include <net/if.h>
68
#include <net/route.h>
69
 
70
#include <netinet/in.h>
71
#include <netinet/in_systm.h>
72
#ifdef INET6
73
#include <netinet/ip6.h>
74
#endif
75
#include <netinet/in_pcb.h>
76
#ifdef INET6
77
#include <netinet6/in6_pcb.h>
78
#endif
79
#include <netinet/in_var.h>
80
#include <netinet/ip_var.h>
81
#ifdef INET6
82
#include <netinet6/ip6_var.h>
83
#endif
84
#include <netinet/tcp.h>
85
#include <netinet/tcp_fsm.h>
86
#include <netinet/tcp_seq.h>
87
#include <netinet/tcp_timer.h>
88
#include <netinet/tcp_var.h>
89
#include <netinet/tcpip.h>
90
#ifdef TCPDEBUG
91
#include <netinet/tcp_debug.h>
92
#endif
93
 
94
#ifdef IPSEC
95
#include <netinet6/ipsec.h>
96
#endif /*IPSEC*/
97
 
98
/*
99
 * TCP protocol interface to socket abstraction.
100
 */
101
extern  char *tcpstates[];      /* XXX ??? */
102
 
103
static int      tcp_attach __P((struct socket *, struct proc *));
104
static int      tcp_connect __P((struct tcpcb *, struct sockaddr *,
105
                                 struct proc *));
106
#ifdef INET6
107
static int      tcp6_connect __P((struct tcpcb *, struct sockaddr *,
108
                                 struct proc *));
109
#endif /* INET6 */
110
static struct tcpcb *
111
                tcp_disconnect __P((struct tcpcb *));
112
static struct tcpcb *
113
                tcp_usrclosed __P((struct tcpcb *));
114
 
115
#ifdef TCPDEBUG
116
#define TCPDEBUG0       int ostate = 0
117
#define TCPDEBUG1()     ostate = tp ? tp->t_state : 0
118
#define TCPDEBUG2(req)  if (tp && (so->so_options & SO_DEBUG)) \
119
                                tcp_trace(TA_USER, ostate, tp, 0, 0, req)
120
#else
121
#define TCPDEBUG0
122
#define TCPDEBUG1()
123
#define TCPDEBUG2(req)
124
#endif
125
 
126
/*
127
 * TCP attaches to socket via pru_attach(), reserving space,
128
 * and an internet control block.
129
 */
130
static int
131
tcp_usr_attach(struct socket *so, int proto, struct proc *p)
132
{
133
        int s = splnet();
134
        int error;
135
        struct inpcb *inp = sotoinpcb(so);
136
        struct tcpcb *tp = 0;
137
        TCPDEBUG0;
138
 
139
        TCPDEBUG1();
140
        if (inp) {
141
                error = EISCONN;
142
                goto out;
143
        }
144
 
145
        error = tcp_attach(so, p);
146
        if (error)
147
                goto out;
148
 
149
        if ((so->so_options & SO_LINGER) && so->so_linger == 0)
150
                so->so_linger = TCP_LINGERTIME;
151
        tp = sototcpcb(so);
152
out:
153
        TCPDEBUG2(PRU_ATTACH);
154
        splx(s);
155
        return error;
156
}
157
 
158
/*
159
 * pru_detach() detaches the TCP protocol from the socket.
160
 * If the protocol state is non-embryonic, then can't
161
 * do this directly: have to initiate a pru_disconnect(),
162
 * which may finish later; embryonic TCB's can just
163
 * be discarded here.
164
 */
165
static int
166
tcp_usr_detach(struct socket *so)
167
{
168
        int s = splnet();
169
        int error = 0;
170
        struct inpcb *inp = sotoinpcb(so);
171
        struct tcpcb *tp;
172
        TCPDEBUG0;
173
 
174
        if (inp == 0) {
175
                splx(s);
176
                return EINVAL;  /* XXX */
177
        }
178
        tp = intotcpcb(inp);
179
        TCPDEBUG1();
180
        tp = tcp_disconnect(tp);
181
 
182
        TCPDEBUG2(PRU_DETACH);
183
        splx(s);
184
        return error;
185
}
186
 
187
#define COMMON_START()  TCPDEBUG0; \
188
                        do { \
189
                                     if (inp == 0) { \
190
                                             splx(s); \
191
                                             return EINVAL; \
192
                                     } \
193
                                     tp = intotcpcb(inp); \
194
                                     TCPDEBUG1(); \
195
                     } while(0)
196
 
197
#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out
198
 
199
 
200
/*
201
 * Give the socket an address.
202
 */
203
static int
204
tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
205
{
206
        int s = splnet();
207
        int error = 0;
208
        struct inpcb *inp = sotoinpcb(so);
209
        struct tcpcb *tp;
210
        struct sockaddr_in *sinp;
211
 
212
        COMMON_START();
213
 
214
        /*
215
         * Must check for multicast addresses and disallow binding
216
         * to them.
217
         */
218
        sinp = (struct sockaddr_in *)nam;
219
        if (sinp->sin_family == AF_INET &&
220
            IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
221
                error = EAFNOSUPPORT;
222
                goto out;
223
        }
224
        error = in_pcbbind(inp, nam, p);
225
        if (error)
226
                goto out;
227
        COMMON_END(PRU_BIND);
228
 
229
}
230
 
231
#ifdef INET6
232
static int
233
tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
234
{
235
        int s = splnet();
236
        int error = 0;
237
        struct inpcb *inp = sotoinpcb(so);
238
        struct tcpcb *tp;
239
        struct sockaddr_in6 *sin6p;
240
 
241
        COMMON_START();
242
 
243
        /*
244
         * Must check for multicast addresses and disallow binding
245
         * to them.
246
         */
247
        sin6p = (struct sockaddr_in6 *)nam;
248
        if (sin6p->sin6_family == AF_INET6 &&
249
            IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
250
                error = EAFNOSUPPORT;
251
                goto out;
252
        }
253
        inp->inp_vflag &= ~INP_IPV4;
254
        inp->inp_vflag |= INP_IPV6;
255
        if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
256
                if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
257
                        inp->inp_vflag |= INP_IPV4;
258
                else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
259
                        struct sockaddr_in sin;
260
 
261
                        in6_sin6_2_sin(&sin, sin6p);
262
                        inp->inp_vflag |= INP_IPV4;
263
                        inp->inp_vflag &= ~INP_IPV6;
264
                        error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
265
                        goto out;
266
                }
267
        }
268
        error = in6_pcbbind(inp, nam, p);
269
        if (error)
270
                goto out;
271
        COMMON_END(PRU_BIND);
272
}
273
#endif /* INET6 */
274
 
275
/*
276
 * Prepare to accept connections.
277
 */
278
static int
279
tcp_usr_listen(struct socket *so, struct proc *p)
280
{
281
        int s = splnet();
282
        int error = 0;
283
        struct inpcb *inp = sotoinpcb(so);
284
        struct tcpcb *tp;
285
 
286
        COMMON_START();
287
        if (inp->inp_lport == 0)
288
                error = in_pcbbind(inp, (struct sockaddr *)0, p);
289
        if (error == 0)
290
                tp->t_state = TCPS_LISTEN;
291
        COMMON_END(PRU_LISTEN);
292
}
293
 
294
#ifdef INET6
295
static int
296
tcp6_usr_listen(struct socket *so, struct proc *p)
297
{
298
        int s = splnet();
299
        int error = 0;
300
        struct inpcb *inp = sotoinpcb(so);
301
        struct tcpcb *tp;
302
 
303
        COMMON_START();
304
        if (inp->inp_lport == 0) {
305
                inp->inp_vflag &= ~INP_IPV4;
306
                if (ip6_mapped_addr_on &&
307
                    (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
308
                        inp->inp_vflag |= INP_IPV4;
309
                error = in6_pcbbind(inp, (struct sockaddr *)0, p);
310
        }
311
        if (error == 0)
312
                tp->t_state = TCPS_LISTEN;
313
        COMMON_END(PRU_LISTEN);
314
}
315
#endif /* INET6 */
316
 
317
/*
318
 * Initiate connection to peer.
319
 * Create a template for use in transmissions on this connection.
320
 * Enter SYN_SENT state, and mark socket as connecting.
321
 * Start keep-alive timer, and seed output sequence space.
322
 * Send initial segment on connection.
323
 */
324
static int
325
tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
326
{
327
        int s = splnet();
328
        int error = 0;
329
        struct inpcb *inp = sotoinpcb(so);
330
        struct tcpcb *tp;
331
        struct sockaddr_in *sinp;
332
 
333
        COMMON_START();
334
 
335
        /*
336
         * Must disallow TCP ``connections'' to multicast addresses.
337
         */
338
        sinp = (struct sockaddr_in *)nam;
339
        if (sinp->sin_family == AF_INET
340
            && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
341
                error = EAFNOSUPPORT;
342
                goto out;
343
        }
344
 
345
 
346
        if ((error = tcp_connect(tp, nam, p)) != 0)
347
                goto out;
348
        error = tcp_output(tp);
349
        COMMON_END(PRU_CONNECT);
350
}
351
 
352
#ifdef INET6
353
static int
354
tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
355
{
356
        int s = splnet();
357
        int error = 0;
358
        struct inpcb *inp = sotoinpcb(so);
359
        struct tcpcb *tp;
360
        struct sockaddr_in6 *sin6p;
361
 
362
        COMMON_START();
363
 
364
        /*
365
         * Must disallow TCP ``connections'' to multicast addresses.
366
         */
367
        sin6p = (struct sockaddr_in6 *)nam;
368
        if (sin6p->sin6_family == AF_INET6
369
            && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
370
                error = EAFNOSUPPORT;
371
                goto out;
372
        }
373
 
374
        if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
375
                struct sockaddr_in sin;
376
 
377
                if (!ip6_mapped_addr_on ||
378
                    (inp->inp_flags & IN6P_IPV6_V6ONLY))
379
                        return(EINVAL);
380
 
381
                in6_sin6_2_sin(&sin, sin6p);
382
                inp->inp_vflag |= INP_IPV4;
383
                inp->inp_vflag &= ~INP_IPV6;
384
                if ((error = tcp_connect(tp, (struct sockaddr *)&sin, p)) != 0)
385
                        goto out;
386
                error = tcp_output(tp);
387
                goto out;
388
        }
389
        inp->inp_vflag &= ~INP_IPV4;
390
        inp->inp_vflag |= INP_IPV6;
391
        if ((error = tcp6_connect(tp, nam, p)) != 0)
392
                goto out;
393
        error = tcp_output(tp);
394
        COMMON_END(PRU_CONNECT);
395
}
396
#endif /* INET6 */
397
 
398
/*
399
 * Initiate disconnect from peer.
400
 * If connection never passed embryonic stage, just drop;
401
 * else if don't need to let data drain, then can just drop anyways,
402
 * else have to begin TCP shutdown process: mark socket disconnecting,
403
 * drain unread data, state switch to reflect user close, and
404
 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
405
 * when peer sends FIN and acks ours.
406
 *
407
 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
408
 */
409
static int
410
tcp_usr_disconnect(struct socket *so)
411
{
412
        int s = splnet();
413
        int error = 0;
414
        struct inpcb *inp = sotoinpcb(so);
415
        struct tcpcb *tp;
416
 
417
        COMMON_START();
418
        tp = tcp_disconnect(tp);
419
        COMMON_END(PRU_DISCONNECT);
420
}
421
 
422
/*
423
 * Accept a connection.  Essentially all the work is
424
 * done at higher levels; just return the address
425
 * of the peer, storing through addr.
426
 */
427
static int
428
tcp_usr_accept(struct socket *so, struct sockaddr **nam)
429
{
430
        int s = splnet();
431
        int error = 0;
432
        struct inpcb *inp = sotoinpcb(so);
433
        struct tcpcb *tp = NULL;
434
        TCPDEBUG0;
435
 
436
        if (so->so_state & SS_ISDISCONNECTED) {
437
                error = ECONNABORTED;
438
                goto out;
439
        }
440
        if (inp == 0) {
441
                splx(s);
442
                return (EINVAL);
443
        }
444
        tp = intotcpcb(inp);
445
        TCPDEBUG1();
446
        in_setpeeraddr(so, nam);
447
        COMMON_END(PRU_ACCEPT);
448
}
449
 
450
#ifdef INET6
451
static int
452
tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
453
{
454
        int s = splnet();
455
        int error = 0;
456
        struct inpcb *inp = sotoinpcb(so);
457
        struct tcpcb *tp = NULL;
458
        TCPDEBUG0;
459
 
460
        if (so->so_state & SS_ISDISCONNECTED) {
461
                error = ECONNABORTED;
462
                goto out;
463
        }
464
        if (inp == 0) {
465
                splx(s);
466
                return (EINVAL);
467
        }
468
        tp = intotcpcb(inp);
469
        TCPDEBUG1();
470
        in6_mapped_peeraddr(so, nam);
471
        COMMON_END(PRU_ACCEPT);
472
}
473
#endif /* INET6 */
474
/*
475
 * Mark the connection as being incapable of further output.
476
 */
477
static int
478
tcp_usr_shutdown(struct socket *so)
479
{
480
        int s = splnet();
481
        int error = 0;
482
        struct inpcb *inp = sotoinpcb(so);
483
        struct tcpcb *tp;
484
 
485
        COMMON_START();
486
        socantsendmore(so);
487
        tp = tcp_usrclosed(tp);
488
        if (tp)
489
                error = tcp_output(tp);
490
        COMMON_END(PRU_SHUTDOWN);
491
}
492
 
493
/*
494
 * After a receive, possibly send window update to peer.
495
 */
496
static int
497
tcp_usr_rcvd(struct socket *so, int flags)
498
{
499
        int s = splnet();
500
        int error = 0;
501
        struct inpcb *inp = sotoinpcb(so);
502
        struct tcpcb *tp;
503
 
504
        COMMON_START();
505
        tcp_output(tp);
506
        COMMON_END(PRU_RCVD);
507
}
508
 
509
/*
510
 * Do a send by putting data in output queue and updating urgent
511
 * marker if URG set.  Possibly send more data.  Unlike the other
512
 * pru_*() routines, the mbuf chains are our responsibility.  We
513
 * must either enqueue them or free them.  The other pru_* routines
514
 * generally are caller-frees.
515
 */
516
static int
517
tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
518
             struct sockaddr *nam, struct mbuf *control, struct proc *p)
519
{
520
        int s = splnet();
521
        int error = 0;
522
        struct inpcb *inp = sotoinpcb(so);
523
        struct tcpcb *tp;
524
#ifdef INET6
525
        int isipv6;
526
#endif
527
        TCPDEBUG0;
528
 
529
        if (inp == NULL) {
530
                /*
531
                 * OOPS! we lost a race, the TCP session got reset after
532
                 * we checked SS_CANTSENDMORE, eg: while doing uiomove or a
533
                 * network interrupt in the non-splnet() section of sosend().
534
                 */
535
                if (m)
536
                        m_freem(m);
537
                if (control)
538
                        m_freem(control);
539
                error = ECONNRESET;     /* XXX EPIPE? */
540
                tp = NULL;
541
                TCPDEBUG1();
542
                goto out;
543
        }
544
#ifdef INET6
545
        isipv6 = nam && nam->sa_family == AF_INET6;
546
#endif /* INET6 */
547
        tp = intotcpcb(inp);
548
        TCPDEBUG1();
549
        if (control) {
550
                /* TCP doesn't do control messages (rights, creds, etc) */
551
                if (control->m_len) {
552
                        m_freem(control);
553
                        if (m)
554
                                m_freem(m);
555
                        error = EINVAL;
556
                        goto out;
557
                }
558
                m_freem(control);       /* empty control, just free it */
559
        }
560
        if(!(flags & PRUS_OOB)) {
561
                sbappend(&so->so_snd, m);
562
                if (nam && tp->t_state < TCPS_SYN_SENT) {
563
                        /*
564
                         * Do implied connect if not yet connected,
565
                         * initialize window to default value, and
566
                         * initialize maxseg/maxopd using peer's cached
567
                         * MSS.
568
                         */
569
#ifdef INET6
570
                        if (isipv6)
571
                                error = tcp6_connect(tp, nam, p);
572
                        else
573
#endif /* INET6 */
574
                        error = tcp_connect(tp, nam, p);
575
                        if (error)
576
                                goto out;
577
                        tp->snd_wnd = TTCP_CLIENT_SND_WND;
578
                        tcp_mss(tp, -1);
579
                }
580
 
581
                if (flags & PRUS_EOF) {
582
                        /*
583
                         * Close the send side of the connection after
584
                         * the data is sent.
585
                         */
586
                        socantsendmore(so);
587
                        tp = tcp_usrclosed(tp);
588
                }
589
                if (tp != NULL) {
590
                        if (flags & PRUS_MORETOCOME)
591
                                tp->t_flags |= TF_MORETOCOME;
592
                        error = tcp_output(tp);
593
                        if (flags & PRUS_MORETOCOME)
594
                                tp->t_flags &= ~TF_MORETOCOME;
595
                }
596
        } else {
597
                if (sbspace(&so->so_snd) < -512) {
598
                        m_freem(m);
599
                        error = ENOBUFS;
600
                        goto out;
601
                }
602
                /*
603
                 * According to RFC961 (Assigned Protocols),
604
                 * the urgent pointer points to the last octet
605
                 * of urgent data.  We continue, however,
606
                 * to consider it to indicate the first octet
607
                 * of data past the urgent section.
608
                 * Otherwise, snd_up should be one lower.
609
                 */
610
                sbappend(&so->so_snd, m);
611
                if (nam && tp->t_state < TCPS_SYN_SENT) {
612
                        /*
613
                         * Do implied connect if not yet connected,
614
                         * initialize window to default value, and
615
                         * initialize maxseg/maxopd using peer's cached
616
                         * MSS.
617
                         */
618
#ifdef INET6
619
                        if (isipv6)
620
                                error = tcp6_connect(tp, nam, p);
621
                        else
622
#endif /* INET6 */
623
                        error = tcp_connect(tp, nam, p);
624
                        if (error)
625
                                goto out;
626
                        tp->snd_wnd = TTCP_CLIENT_SND_WND;
627
                        tcp_mss(tp, -1);
628
                }
629
                tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
630
                tp->t_force = 1;
631
                error = tcp_output(tp);
632
                tp->t_force = 0;
633
        }
634
        COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB :
635
                   ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
636
}
637
 
638
/*
639
 * Abort the TCP.
640
 */
641
static int
642
tcp_usr_abort(struct socket *so)
643
{
644
        int s = splnet();
645
        int error = 0;
646
        struct inpcb *inp = sotoinpcb(so);
647
        struct tcpcb *tp;
648
 
649
        COMMON_START();
650
        tp = tcp_drop(tp, ECONNABORTED);
651
        COMMON_END(PRU_ABORT);
652
}
653
 
654
/*
655
 * Receive out-of-band data.
656
 */
657
static int
658
tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
659
{
660
        int s = splnet();
661
        int error = 0;
662
        struct inpcb *inp = sotoinpcb(so);
663
        struct tcpcb *tp;
664
 
665
        COMMON_START();
666
        if ((so->so_oobmark == 0 &&
667
             (so->so_state & SS_RCVATMARK) == 0) ||
668
            so->so_options & SO_OOBINLINE ||
669
            tp->t_oobflags & TCPOOB_HADDATA) {
670
                error = EINVAL;
671
                goto out;
672
        }
673
        if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
674
                error = EWOULDBLOCK;
675
                goto out;
676
        }
677
        m->m_len = 1;
678
        *mtod(m, caddr_t) = tp->t_iobc;
679
        if ((flags & MSG_PEEK) == 0)
680
                tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
681
        COMMON_END(PRU_RCVOOB);
682
}
683
 
684
/* xxx - should be const */
685
struct pr_usrreqs tcp_usrreqs = {
686
        tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
687
        tcp_usr_connect, pru_connect2_notsupp, in_control, tcp_usr_detach,
688
        tcp_usr_disconnect, tcp_usr_listen, in_setpeeraddr, tcp_usr_rcvd,
689
        tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
690
        in_setsockaddr, sosend, soreceive, sopoll
691
};
692
 
693
#ifdef INET6
694
struct pr_usrreqs tcp6_usrreqs = {
695
        tcp_usr_abort, tcp6_usr_accept, tcp_usr_attach, tcp6_usr_bind,
696
        tcp6_usr_connect, pru_connect2_notsupp, in6_control, tcp_usr_detach,
697
        tcp_usr_disconnect, tcp6_usr_listen, in6_mapped_peeraddr, tcp_usr_rcvd,
698
        tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
699
        in6_mapped_sockaddr, sosend, soreceive, sopoll
700
};
701
#endif /* INET6 */
702
 
703
/*
704
 * Common subroutine to open a TCP connection to remote host specified
705
 * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
706
 * port number if needed.  Call in_pcbladdr to do the routing and to choose
707
 * a local host address (interface).  If there is an existing incarnation
708
 * of the same connection in TIME-WAIT state and if the remote host was
709
 * sending CC options and if the connection duration was < MSL, then
710
 * truncate the previous TIME-WAIT state and proceed.
711
 * Initialize connection parameters and enter SYN-SENT state.
712
 */
713
static int
714
tcp_connect(tp, nam, p)
715
        register struct tcpcb *tp;
716
        struct sockaddr *nam;
717
        struct proc *p;
718
{
719
        struct inpcb *inp = tp->t_inpcb, *oinp;
720
        struct socket *so = inp->inp_socket;
721
        struct tcpcb *otp;
722
        struct sockaddr_in *sin = (struct sockaddr_in *)nam;
723
        struct sockaddr_in *ifaddr;
724
        struct rmxp_tao *taop;
725
        struct rmxp_tao tao_noncached;
726
        int error;
727
 
728
        if (inp->inp_lport == 0) {
729
                error = in_pcbbind(inp, (struct sockaddr *)0, p);
730
                if (error)
731
                        return error;
732
        }
733
 
734
        /*
735
         * Cannot simply call in_pcbconnect, because there might be an
736
         * earlier incarnation of this same connection still in
737
         * TIME_WAIT state, creating an ADDRINUSE error.
738
         */
739
        error = in_pcbladdr(inp, nam, &ifaddr);
740
        if (error)
741
                return error;
742
        oinp = in_pcblookup_hash(inp->inp_pcbinfo,
743
            sin->sin_addr, sin->sin_port,
744
            inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
745
                                                : ifaddr->sin_addr,
746
            inp->inp_lport,  0, NULL);
747
        if (oinp) {
748
                if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
749
                otp->t_state == TCPS_TIME_WAIT &&
750
                    (ticks - otp->t_starttime) < tcp_msl &&
751
                    (otp->t_flags & TF_RCVD_CC))
752
                        otp = tcp_close(otp);
753
                else
754
                        return EADDRINUSE;
755
        }
756
        if (inp->inp_laddr.s_addr == INADDR_ANY)
757
                inp->inp_laddr = ifaddr->sin_addr;
758
        inp->inp_faddr = sin->sin_addr;
759
        inp->inp_fport = sin->sin_port;
760
        in_pcbrehash(inp);
761
 
762
        /* Compute window scaling to request.  */
763
        while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
764
            (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
765
                tp->request_r_scale++;
766
 
767
        soisconnecting(so);
768
        tcpstat.tcps_connattempt++;
769
        tp->t_state = TCPS_SYN_SENT;
770
        callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
771
        tp->iss = tcp_new_isn(tp);
772
        tcp_sendseqinit(tp);
773
 
774
        /*
775
         * Generate a CC value for this connection and
776
         * check whether CC or CCnew should be used.
777
         */
778
        if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
779
                taop = &tao_noncached;
780
                bzero(taop, sizeof(*taop));
781
        }
782
 
783
        tp->cc_send = CC_INC(tcp_ccgen);
784
        if (taop->tao_ccsent != 0 &&
785
            CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
786
                taop->tao_ccsent = tp->cc_send;
787
        } else {
788
                taop->tao_ccsent = 0;
789
                tp->t_flags |= TF_SENDCCNEW;
790
        }
791
 
792
        return 0;
793
}
794
 
795
#ifdef INET6
796
static int
797
tcp6_connect(tp, nam, p)
798
        register struct tcpcb *tp;
799
        struct sockaddr *nam;
800
        struct proc *p;
801
{
802
        struct inpcb *inp = tp->t_inpcb, *oinp;
803
        struct socket *so = inp->inp_socket;
804
        struct tcpcb *otp;
805
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
806
        struct in6_addr *addr6;
807
        struct rmxp_tao *taop;
808
        struct rmxp_tao tao_noncached;
809
        int error;
810
 
811
        if (inp->inp_lport == 0) {
812
                error = in6_pcbbind(inp, (struct sockaddr *)0, p);
813
                if (error)
814
                        return error;
815
        }
816
 
817
        /*
818
         * Cannot simply call in_pcbconnect, because there might be an
819
         * earlier incarnation of this same connection still in
820
         * TIME_WAIT state, creating an ADDRINUSE error.
821
         */
822
        error = in6_pcbladdr(inp, nam, &addr6);
823
        if (error)
824
                return error;
825
        oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
826
                                  &sin6->sin6_addr, sin6->sin6_port,
827
                                  IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
828
                                  ? addr6
829
                                  : &inp->in6p_laddr,
830
                                  inp->inp_lport,  0, NULL);
831
        if (oinp) {
832
                if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
833
                    otp->t_state == TCPS_TIME_WAIT &&
834
                    (ticks - otp->t_starttime) < tcp_msl &&
835
                    (otp->t_flags & TF_RCVD_CC))
836
                        otp = tcp_close(otp);
837
                else
838
                        return EADDRINUSE;
839
        }
840
        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
841
                inp->in6p_laddr = *addr6;
842
        inp->in6p_faddr = sin6->sin6_addr;
843
        inp->inp_fport = sin6->sin6_port;
844
        if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != (u_int32_t)NULL)
845
                inp->in6p_flowinfo = sin6->sin6_flowinfo;
846
        in_pcbrehash(inp);
847
 
848
        /* Compute window scaling to request.  */
849
        while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
850
            (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
851
                tp->request_r_scale++;
852
 
853
        soisconnecting(so);
854
        tcpstat.tcps_connattempt++;
855
        tp->t_state = TCPS_SYN_SENT;
856
        callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
857
        tp->iss = tcp_new_isn(tp);
858
        tcp_sendseqinit(tp);
859
 
860
        /*
861
         * Generate a CC value for this connection and
862
         * check whether CC or CCnew should be used.
863
         */
864
        if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
865
                taop = &tao_noncached;
866
                bzero(taop, sizeof(*taop));
867
        }
868
 
869
        tp->cc_send = CC_INC(tcp_ccgen);
870
        if (taop->tao_ccsent != 0 &&
871
            CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
872
                taop->tao_ccsent = tp->cc_send;
873
        } else {
874
                taop->tao_ccsent = 0;
875
                tp->t_flags |= TF_SENDCCNEW;
876
        }
877
 
878
        return 0;
879
}
880
#endif /* INET6 */
881
 
882
/*
883
 * The new sockopt interface makes it possible for us to block in the
884
 * copyin/out step (if we take a page fault).  Taking a page fault at
885
 * splnet() is probably a Bad Thing.  (Since sockets and pcbs both now
886
 * use TSM, there probably isn't any need for this function to run at
887
 * splnet() any more.  This needs more examination.)
888
 */
889
int
890
tcp_ctloutput(so, sopt)
891
        struct socket *so;
892
        struct sockopt *sopt;
893
{
894
        int     error, opt, optval, s;
895
        struct  inpcb *inp;
896
        struct  tcpcb *tp;
897
 
898
        error = 0;
899
        s = splnet();           /* XXX */
900
        inp = sotoinpcb(so);
901
        if (inp == NULL) {
902
                splx(s);
903
                return (ECONNRESET);
904
        }
905
        if (sopt->sopt_level != IPPROTO_TCP) {
906
#ifdef INET6
907
                if (INP_CHECK_SOCKAF(so, AF_INET6))
908
                        error = ip6_ctloutput(so, sopt);
909
                else
910
#endif /* INET6 */
911
                error = ip_ctloutput(so, sopt);
912
                splx(s);
913
                return (error);
914
        }
915
        tp = intotcpcb(inp);
916
 
917
        switch (sopt->sopt_dir) {
918
        case SOPT_SET:
919
                switch (sopt->sopt_name) {
920
                case TCP_NODELAY:
921
                case TCP_NOOPT:
922
                case TCP_NOPUSH:
923
                        error = sooptcopyin(sopt, &optval, sizeof optval,
924
                                            sizeof optval);
925
                        if (error)
926
                                break;
927
 
928
                        switch (sopt->sopt_name) {
929
                        case TCP_NODELAY:
930
                                opt = TF_NODELAY;
931
                                break;
932
                        case TCP_NOOPT:
933
                                opt = TF_NOOPT;
934
                                break;
935
                        case TCP_NOPUSH:
936
                                opt = TF_NOPUSH;
937
                                break;
938
                        default:
939
                                opt = 0; /* dead code to fool gcc */
940
                                break;
941
                        }
942
 
943
                        if (optval)
944
                                tp->t_flags |= opt;
945
                        else
946
                                tp->t_flags &= ~opt;
947
                        break;
948
 
949
                case TCP_MAXSEG:
950
                        error = sooptcopyin(sopt, &optval, sizeof optval,
951
                                            sizeof optval);
952
                        if (error)
953
                                break;
954
 
955
                        if (optval > 0 && optval <= tp->t_maxseg)
956
                                tp->t_maxseg = optval;
957
                        else
958
                                error = EINVAL;
959
                        break;
960
 
961
                default:
962
                        error = ENOPROTOOPT;
963
                        break;
964
                }
965
                break;
966
 
967
        case SOPT_GET:
968
                switch (sopt->sopt_name) {
969
                case TCP_NODELAY:
970
                        optval = tp->t_flags & TF_NODELAY;
971
                        break;
972
                case TCP_MAXSEG:
973
                        optval = tp->t_maxseg;
974
                        break;
975
                case TCP_NOOPT:
976
                        optval = tp->t_flags & TF_NOOPT;
977
                        break;
978
                case TCP_NOPUSH:
979
                        optval = tp->t_flags & TF_NOPUSH;
980
                        break;
981
                default:
982
                        error = ENOPROTOOPT;
983
                        break;
984
                }
985
                if (error == 0)
986
                        error = sooptcopyout(sopt, &optval, sizeof optval);
987
                break;
988
        }
989
        splx(s);
990
        return (error);
991
}
992
 
993
/*
994
 * tcp_sendspace and tcp_recvspace are the default send and receive window
995
 * sizes, respectively.  These are obsolescent (this information should
996
 * be set by the route).
997
 */
998
u_long  tcp_sendspace = 1024*16;
999
u_long  tcp_recvspace = 1024*16;
1000
 
1001
/*
1002
 * Attach TCP protocol to socket, allocating
1003
 * internet protocol control block, tcp control block,
1004
 * bufer space, and entering LISTEN state if to accept connections.
1005
 */
1006
static int
1007
tcp_attach(so, p)
1008
        struct socket *so;
1009
        struct proc *p;
1010
{
1011
        register struct tcpcb *tp;
1012
        struct inpcb *inp;
1013
        int error;
1014
#ifdef INET6
1015
        int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != (int)NULL;
1016
#endif
1017
 
1018
        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1019
                error = soreserve(so, tcp_sendspace, tcp_recvspace);
1020
                if (error)
1021
                        return (error);
1022
        }
1023
        error = in_pcballoc(so, &tcbinfo, p);
1024
        if (error)
1025
                return (error);
1026
        inp = sotoinpcb(so);
1027
#ifdef INET6
1028
        if (isipv6) {
1029
                inp->inp_vflag |= INP_IPV6;
1030
                inp->in6p_hops = -1;    /* use kernel default */
1031
        }
1032
        else
1033
#endif
1034
        inp->inp_vflag |= INP_IPV4;
1035
        tp = tcp_newtcpcb(inp);
1036
        if (tp == 0) {
1037
                int nofd = so->so_state & SS_NOFDREF;   /* XXX */
1038
 
1039
                so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
1040
#ifdef INET6
1041
                if (isipv6)
1042
                        in6_pcbdetach(inp);
1043
                else
1044
#endif
1045
                in_pcbdetach(inp);
1046
                so->so_state |= nofd;
1047
                return (ENOBUFS);
1048
        }
1049
        tp->t_state = TCPS_CLOSED;
1050
        return (0);
1051
}
1052
 
1053
/*
1054
 * Initiate (or continue) disconnect.
1055
 * If embryonic state, just send reset (once).
1056
 * If in ``let data drain'' option and linger null, just drop.
1057
 * Otherwise (hard), mark socket disconnecting and drop
1058
 * current input data; switch states based on user close, and
1059
 * send segment to peer (with FIN).
1060
 */
1061
static struct tcpcb *
1062
tcp_disconnect(tp)
1063
        register struct tcpcb *tp;
1064
{
1065
        struct socket *so = tp->t_inpcb->inp_socket;
1066
 
1067
        if (tp->t_state < TCPS_ESTABLISHED)
1068
                tp = tcp_close(tp);
1069
        else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
1070
                tp = tcp_drop(tp, 0);
1071
        else {
1072
                soisdisconnecting(so);
1073
                sbflush(&so->so_rcv);
1074
                tp = tcp_usrclosed(tp);
1075
                if (tp)
1076
                        (void) tcp_output(tp);
1077
        }
1078
        return (tp);
1079
}
1080
 
1081
/*
1082
 * User issued close, and wish to trail through shutdown states:
1083
 * if never received SYN, just forget it.  If got a SYN from peer,
1084
 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
1085
 * If already got a FIN from peer, then almost done; go to LAST_ACK
1086
 * state.  In all other cases, have already sent FIN to peer (e.g.
1087
 * after PRU_SHUTDOWN), and just have to play tedious game waiting
1088
 * for peer to send FIN or not respond to keep-alives, etc.
1089
 * We can let the user exit from the close as soon as the FIN is acked.
1090
 */
1091
static struct tcpcb *
1092
tcp_usrclosed(tp)
1093
        register struct tcpcb *tp;
1094
{
1095
 
1096
        switch (tp->t_state) {
1097
 
1098
        case TCPS_CLOSED:
1099
        case TCPS_LISTEN:
1100
                tp->t_state = TCPS_CLOSED;
1101
                tp = tcp_close(tp);
1102
                break;
1103
 
1104
        case TCPS_SYN_SENT:
1105
        case TCPS_SYN_RECEIVED:
1106
                tp->t_flags |= TF_NEEDFIN;
1107
                break;
1108
 
1109
        case TCPS_ESTABLISHED:
1110
                tp->t_state = TCPS_FIN_WAIT_1;
1111
                break;
1112
 
1113
        case TCPS_CLOSE_WAIT:
1114
                tp->t_state = TCPS_LAST_ACK;
1115
                break;
1116
        }
1117
        if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
1118
                soisdisconnected(tp->t_inpcb->inp_socket);
1119
                /* To prevent the connection hanging in FIN_WAIT_2 forever. */
1120
                if (tp->t_state == TCPS_FIN_WAIT_2)
1121
                        callout_reset(tp->tt_2msl, tcp_maxidle,
1122
                                      tcp_timer_2msl, tp);
1123
        }
1124
        return (tp);
1125
}
1126
 

powered by: WebSVN 2.1.0

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