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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      sys/netinet/tcp_usrreq.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: tcp_usrreq.c,v 1.37 1999/12/08 06:50:20 itojun Exp $  */
34
/*      $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
35
 
36
/*
37
 * Copyright (c) 1982, 1986, 1988, 1993
38
 *      The Regents of the University of California.  All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. All advertising materials mentioning features or use of this software
49
 *    must display the following acknowledgement:
50
 *      This product includes software developed by the University of
51
 *      California, Berkeley and its contributors.
52
 * 4. Neither the name of the University nor the names of its contributors
53
 *    may be used to endorse or promote products derived from this software
54
 *    without specific prior written permission.
55
 *
56
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66
 * SUCH DAMAGE.
67
 *
68
 *      @(#)tcp_usrreq.c        8.2 (Berkeley) 1/3/94
69
 */
70
 
71
/*
72
%%% portions-copyright-nrl-95
73
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
74
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
75
Reserved. All rights under this copyright have been assigned to the US
76
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
77
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
78
software.
79
You should have received a copy of the license with this software. If you
80
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
81
*/
82
 
83
#include <sys/param.h>
84
#ifndef __ECOS
85
#include <sys/systm.h>
86
#endif
87
#include <sys/kernel.h>
88
#include <sys/malloc.h>
89
#include <sys/mbuf.h>
90
#include <sys/socket.h>
91
#include <sys/socketvar.h>
92
#include <sys/protosw.h>
93
#include <sys/errno.h>
94
#ifndef __ECOS
95
#include <sys/stat.h>
96
#include <sys/proc.h>
97
#include <sys/ucred.h>
98
 
99
#include <vm/vm.h>
100
#include <sys/sysctl.h>
101
#endif
102
 
103
#include <net/if.h>
104
#include <net/route.h>
105
 
106
#include <netinet/in.h>
107
#include <netinet/in_systm.h>
108
#include <netinet/in_var.h>
109
#include <netinet/ip.h>
110
#include <netinet/in_pcb.h>
111
#include <netinet/ip_var.h>
112
#include <netinet/tcp.h>
113
#include <netinet/tcp_fsm.h>
114
#include <netinet/tcp_seq.h>
115
#include <netinet/tcp_timer.h>
116
#include <netinet/tcp_var.h>
117
#include <netinet/tcpip.h>
118
#include <netinet/tcp_debug.h>
119
#ifndef __ECOS
120
#include <dev/rndvar.h>
121
#endif
122
 
123
#ifdef IPSEC
124
extern int      check_ipsec_policy __P((struct inpcb *, u_int32_t));
125
#endif
126
 
127
#ifdef INET6
128
#include <sys/domain.h>
129
#endif /* INET6 */
130
 
131
/*
132
 * TCP protocol interface to socket abstraction.
133
 */
134
extern  char *tcpstates[];
135
extern  int tcptv_keep_init;
136
 
137
/* from in_pcb.c */
138
extern  struct baddynamicports baddynamicports;
139
 
140
int tcp_ident __P((void *, size_t *, void *, size_t));
141
 
142
#if defined(INET6) && !defined(TCP6)
143
int
144
tcp6_usrreq(so, req, m, nam, control, p)
145
        struct socket *so;
146
        int req;
147
        struct mbuf *m, *nam, *control;
148
        struct proc *p;
149
{
150
        return tcp_usrreq(so, req, m, nam, control);
151
}
152
#endif
153
 
154
/*
155
 * Process a TCP user request for TCP tb.  If this is a send request
156
 * then m is the mbuf chain of send data.  If this is a timer expiration
157
 * (called from the software clock routine), then timertype tells which timer.
158
 */
159
/*ARGSUSED*/
160
int
161
tcp_usrreq(so, req, m, nam, control)
162
        struct socket *so;
163
        int req;
164
        struct mbuf *m, *nam, *control;
165
{
166
        struct sockaddr_in *sin;
167
        register struct inpcb *inp;
168
        register struct tcpcb *tp = NULL;
169
        int s;
170
        int error = 0;
171
        int ostate;
172
 
173
        if (req == PRU_CONTROL) {
174
#ifdef INET6
175
                if (sotopf(so) == PF_INET6)
176
                        return in6_control(so, (u_long)m, (caddr_t)nam,
177
                            (struct ifnet *)control, 0);
178
                else
179
#endif /* INET6 */
180
                        return (in_control(so, (u_long)m, (caddr_t)nam,
181
                            (struct ifnet *)control));
182
        }
183
        if (control && control->m_len) {
184
                m_freem(control);
185
                if (m)
186
                        m_freem(m);
187
                return (EINVAL);
188
        }
189
 
190
        s = splsoftnet();
191
        inp = sotoinpcb(so);
192
        /*
193
         * When a TCP is attached to a socket, then there will be
194
         * a (struct inpcb) pointed at by the socket, and this
195
         * structure will point at a subsidary (struct tcpcb).
196
         */
197
        if (inp == 0 && req != PRU_ATTACH) {
198
                splx(s);
199
                /*
200
                 * The following corrects an mbuf leak under rare
201
                 * circumstances
202
                 */
203
                if (m && (req == PRU_SEND || req == PRU_SENDOOB))
204
                        m_freem(m);
205
                return (EINVAL);                /* XXX */
206
        }
207
        if (inp) {
208
                tp = intotcpcb(inp);
209
                /* WHAT IF TP IS 0? */
210
#ifdef KPROF
211
                tcp_acounts[tp->t_state][req]++;
212
#endif
213
                ostate = tp->t_state;
214
        } else
215
                ostate = 0;
216
        switch (req) {
217
 
218
        /*
219
         * TCP attaches to socket via PRU_ATTACH, reserving space,
220
         * and an internet control block.
221
         */
222
        case PRU_ATTACH:
223
                if (inp) {
224
                        error = EISCONN;
225
                        break;
226
                }
227
                error = tcp_attach(so);
228
                if (error)
229
                        break;
230
                if ((so->so_options & SO_LINGER) && so->so_linger == 0)
231
                        so->so_linger = TCP_LINGERTIME;
232
                tp = sototcpcb(so);
233
                break;
234
 
235
        /*
236
         * PRU_DETACH detaches the TCP protocol from the socket.
237
         * If the protocol state is non-embryonic, then can't
238
         * do this directly: have to initiate a PRU_DISCONNECT,
239
         * which may finish later; embryonic TCB's can just
240
         * be discarded here.
241
         */
242
        case PRU_DETACH:
243
                tp = tcp_disconnect(tp);
244
                break;
245
 
246
        /*
247
         * Give the socket an address.
248
         */
249
        case PRU_BIND:
250
#ifdef INET6
251
                if (inp->inp_flags & INP_IPV6)
252
                        error = in6_pcbbind(inp, nam);
253
                else
254
#endif
255
                        error = in_pcbbind(inp, nam);
256
                if (error)
257
                        break;
258
#ifdef INET6
259
                /*
260
                 * If we bind to an address, set up the tp->pf accordingly!
261
                 */
262
                if (inp->inp_flags & INP_IPV6) {
263
                        /* If a PF_INET6 socket... */
264
                        if (inp->inp_flags & INP_IPV6_MAPPED)
265
                                tp->pf = AF_INET;
266
                        else if ((inp->inp_flags & INP_IPV6_UNDEC) == 0)
267
                                tp->pf = AF_INET6;
268
                        /* else tp->pf is still 0. */
269
                }
270
                /* else socket is PF_INET, and tp->pf is PF_INET. */
271
#endif /* INET6 */
272
                break;
273
 
274
        /*
275
         * Prepare to accept connections.
276
         */
277
        case PRU_LISTEN:
278
                if (inp->inp_lport == 0) {
279
#ifdef INET6
280
                        if (inp->inp_flags & INP_IPV6)
281
                                error = in6_pcbbind(inp, NULL);
282
                        else
283
#endif
284
                                error = in_pcbbind(inp, NULL);
285
                }
286
                /* If the in_pcbbind() above is called, the tp->pf
287
                   should still be whatever it was before. */
288
                if (error == 0)
289
                        tp->t_state = TCPS_LISTEN;
290
                break;
291
 
292
        /*
293
         * Initiate connection to peer.
294
         * Create a template for use in transmissions on this connection.
295
         * Enter SYN_SENT state, and mark socket as connecting.
296
         * Start keep-alive timer, and seed output sequence space.
297
         * Send initial segment on connection.
298
         */
299
        case PRU_CONNECT:
300
                sin = mtod(nam, struct sockaddr_in *);
301
 
302
#ifdef INET6
303
                if (sin->sin_family == AF_INET6) {
304
                        struct in6_addr *in6_addr = &mtod(nam,
305
                            struct sockaddr_in6 *)->sin6_addr;
306
 
307
                        if (IN6_IS_ADDR_UNSPECIFIED(in6_addr) ||
308
                            IN6_IS_ADDR_MULTICAST(in6_addr) ||
309
                            (IN6_IS_ADDR_V4MAPPED(in6_addr) &&
310
                            ((in6_addr->s6_addr32[3] == INADDR_ANY) ||
311
                            IN_MULTICAST(in6_addr->s6_addr32[3]) ||
312
                            in_broadcast(sin->sin_addr, NULL)))) {
313
                                error = EINVAL;
314
                                break;
315
                        }
316
 
317
                        if (inp->inp_lport == 0) {
318
                                error = in6_pcbbind(inp, NULL);
319
                                if (error)
320
                                        break;
321
                        }
322
                        error = in6_pcbconnect(inp, nam);
323
                } else if (sin->sin_family == AF_INET)
324
#endif /* INET6 */
325
                {
326
                        if ((sin->sin_addr.s_addr == INADDR_ANY) ||
327
                            IN_MULTICAST(sin->sin_addr.s_addr) ||
328
                            in_broadcast(sin->sin_addr, NULL)) {
329
                                error = EINVAL;
330
                                break;
331
                        }
332
 
333
                        /* Trying to connect to some broadcast address */
334
                        if (in_broadcast(sin->sin_addr, NULL)) {
335
                                error = EINVAL;
336
                                break;
337
                        }
338
 
339
                        if (inp->inp_lport == 0) {
340
                                error = in_pcbbind(inp, NULL);
341
                                if (error)
342
                                        break;
343
                        }
344
                        error = in_pcbconnect(inp, nam);
345
                }
346
 
347
                if (error)
348
                        break;
349
 
350
#ifdef INET6
351
                /*
352
                 * With a connection, I now know the version of IP
353
                 * is in use and hence can set tp->pf with authority.
354
                 */
355
                if (inp->inp_flags & INP_IPV6) {
356
                        if (inp->inp_flags & INP_IPV6_MAPPED)
357
                                tp->pf = PF_INET;
358
                        else
359
                                tp->pf = PF_INET6;
360
                }
361
                /* else I'm a PF_INET socket, and hence tp->pf is PF_INET. */
362
#endif /* INET6 */
363
 
364
                tp->t_template = tcp_template(tp);
365
                if (tp->t_template == 0) {
366
                        in_pcbdisconnect(inp);
367
                        error = ENOBUFS;
368
                        break;
369
                }
370
 
371
#ifdef INET6
372
                if ((inp->inp_flags & INP_IPV6) && (tp->pf == PF_INET)) {
373
                        inp->inp_ip.ip_ttl = ip_defttl;
374
                        inp->inp_ip.ip_tos = 0;
375
                }
376
#endif /* INET6 */
377
 
378
                so->so_state |= SS_CONNECTOUT;
379
                /* Compute window scaling to request.  */
380
                while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
381
                    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
382
                        tp->request_r_scale++;
383
                soisconnecting(so);
384
                tcpstat.tcps_connattempt++;
385
                tp->t_state = TCPS_SYN_SENT;
386
                tp->t_timer[TCPT_KEEP] = tcptv_keep_init;
387
                tp->iss = tcp_iss;
388
#ifdef TCP_COMPAT_42
389
                tcp_iss += TCP_ISSINCR/2;
390
#else /* TCP_COMPAT_42 */
391
                tcp_iss += arc4random() % TCP_ISSINCR + 1;
392
#endif /* !TCP_COMPAT_42 */
393
                tcp_sendseqinit(tp);
394
#if defined(TCP_SACK) || defined(TCP_NEWRENO)
395
                tp->snd_last = tp->snd_una;
396
#endif
397
#if defined(TCP_SACK) && defined(TCP_FACK)
398
                tp->snd_fack = tp->snd_una;
399
                tp->retran_data = 0;
400
                tp->snd_awnd = 0;
401
#endif
402
                error = tcp_output(tp);
403
                break;
404
 
405
        /*
406
         * Create a TCP connection between two sockets.
407
         */
408
        case PRU_CONNECT2:
409
                error = EOPNOTSUPP;
410
                break;
411
 
412
        /*
413
         * Initiate disconnect from peer.
414
         * If connection never passed embryonic stage, just drop;
415
         * else if don't need to let data drain, then can just drop anyways,
416
         * else have to begin TCP shutdown process: mark socket disconnecting,
417
         * drain unread data, state switch to reflect user close, and
418
         * send segment (e.g. FIN) to peer.  Socket will be really disconnected
419
         * when peer sends FIN and acks ours.
420
         *
421
         * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
422
         */
423
        case PRU_DISCONNECT:
424
                tp = tcp_disconnect(tp);
425
                break;
426
 
427
        /*
428
         * Accept a connection.  Essentially all the work is
429
         * done at higher levels; just return the address
430
         * of the peer, storing through addr.
431
         */
432
        case PRU_ACCEPT:
433
#ifdef INET6
434
                if (inp->inp_flags & INP_IPV6)
435
                        in6_setpeeraddr(inp, nam);
436
                else
437
#endif
438
                        in_setpeeraddr(inp, nam);
439
                break;
440
 
441
        /*
442
         * Mark the connection as being incapable of further output.
443
         */
444
        case PRU_SHUTDOWN:
445
                if (so->so_state & SS_CANTSENDMORE)
446
                        break;
447
                socantsendmore(so);
448
                tp = tcp_usrclosed(tp);
449
                if (tp)
450
                        error = tcp_output(tp);
451
                break;
452
 
453
        /*
454
         * After a receive, possibly send window update to peer.
455
         */
456
        case PRU_RCVD:
457
                (void) tcp_output(tp);
458
                break;
459
 
460
        /*
461
         * Do a send by putting data in output queue and updating urgent
462
         * marker if URG set.  Possibly send more data.
463
         */
464
        case PRU_SEND:
465
#ifdef IPSEC
466
                error = check_ipsec_policy(inp, 0);
467
                if (error)
468
                        break;
469
#endif
470
                sbappend(&so->so_snd, m);
471
                error = tcp_output(tp);
472
                break;
473
 
474
        /*
475
         * Abort the TCP.
476
         */
477
        case PRU_ABORT:
478
                tp = tcp_drop(tp, ECONNABORTED);
479
                break;
480
 
481
        case PRU_SENSE:
482
#ifndef __ECOS
483
                ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
484
#endif
485
                (void) splx(s);
486
                return (0);
487
 
488
        case PRU_RCVOOB:
489
                if ((so->so_oobmark == 0 &&
490
                    (so->so_state & SS_RCVATMARK) == 0) ||
491
                    so->so_options & SO_OOBINLINE ||
492
                    tp->t_oobflags & TCPOOB_HADDATA) {
493
                        error = EINVAL;
494
                        break;
495
                }
496
                if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
497
                        error = EWOULDBLOCK;
498
                        break;
499
                }
500
                m->m_len = 1;
501
                *mtod(m, caddr_t) = tp->t_iobc;
502
                if (((long)nam & MSG_PEEK) == 0)
503
                        tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
504
                break;
505
 
506
        case PRU_SENDOOB:
507
                if (sbspace(&so->so_snd) < -512) {
508
                        m_freem(m);
509
                        error = ENOBUFS;
510
                        break;
511
                }
512
                /*
513
                 * According to RFC961 (Assigned Protocols),
514
                 * the urgent pointer points to the last octet
515
                 * of urgent data.  We continue, however,
516
                 * to consider it to indicate the first octet
517
                 * of data past the urgent section.
518
                 * Otherwise, snd_up should be one lower.
519
                 */
520
                sbappend(&so->so_snd, m);
521
                tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
522
                tp->t_force = 1;
523
                error = tcp_output(tp);
524
                tp->t_force = 0;
525
                break;
526
 
527
        case PRU_SOCKADDR:
528
#ifdef INET6
529
                if (inp->inp_flags & INP_IPV6)
530
                        in6_setsockaddr(inp, nam);
531
                else
532
#endif
533
                        in_setsockaddr(inp, nam);
534
                break;
535
 
536
        case PRU_PEERADDR:
537
#ifdef INET6
538
                if (inp->inp_flags & INP_IPV6)
539
                        in6_setpeeraddr(inp, nam);
540
                else
541
#endif
542
                        in_setpeeraddr(inp, nam);
543
                break;
544
 
545
        /*
546
         * TCP slow timer went off; going through this
547
         * routine for tracing's sake.
548
         */
549
        case PRU_SLOWTIMO:
550
                tp = tcp_timers(tp, (long)nam);
551
                req |= (long)nam << 8;          /* for debug's sake */
552
                break;
553
 
554
        default:
555
                panic("tcp_usrreq");
556
        }
557
#ifdef TCPDEBUG
558
        if (tp && (so->so_options & SO_DEBUG))
559
                tcp_trace(TA_USER, ostate, tp, (caddr_t)0, req, 0);
560
#endif /* TCPDEBUG */
561
        splx(s);
562
        return (error);
563
}
564
 
565
int
566
tcp_ctloutput(op, so, level, optname, mp)
567
        int op;
568
        struct socket *so;
569
        int level, optname;
570
        struct mbuf **mp;
571
{
572
        int error = 0, s;
573
        struct inpcb *inp;
574
        register struct tcpcb *tp;
575
        register struct mbuf *m;
576
        register int i;
577
 
578
        s = splsoftnet();
579
        inp = sotoinpcb(so);
580
        if (inp == NULL) {
581
                splx(s);
582
                if (op == PRCO_SETOPT && *mp)
583
                        (void) m_free(*mp);
584
                return (ECONNRESET);
585
        }
586
#ifdef INET6
587
        tp = intotcpcb(inp);
588
#endif /* INET6 */
589
        if (level != IPPROTO_TCP) {
590
#ifdef INET6
591
                /*
592
                 * Not sure if this is the best approach.
593
                 * It seems to be, but we don't set tp->pf until the connection
594
                 * is established, which may lead to confusion in the case of
595
                 * AF_INET6 sockets which get SET/GET options for IPv4.
596
                 */
597
                if (tp->pf == PF_INET6)
598
                        error = ip6_ctloutput(op, so, level, optname, mp);
599
                else
600
#endif /* INET6 */
601
                        error = ip_ctloutput(op, so, level, optname, mp);
602
                splx(s);
603
                return (error);
604
        }
605
#ifndef INET6
606
        tp = intotcpcb(inp);
607
#endif /* !INET6 */
608
 
609
        switch (op) {
610
 
611
        case PRCO_SETOPT:
612
                m = *mp;
613
                switch (optname) {
614
 
615
                case TCP_NODELAY:
616
                        if (m == NULL || m->m_len < sizeof (int))
617
                                error = EINVAL;
618
                        else if (*mtod(m, int *))
619
                                tp->t_flags |= TF_NODELAY;
620
                        else
621
                                tp->t_flags &= ~TF_NODELAY;
622
                        break;
623
 
624
                case TCP_MAXSEG:
625
                        if (m == NULL || m->m_len < sizeof (int)) {
626
                                error = EINVAL;
627
                                break;
628
                        }
629
 
630
                        i = *mtod(m, int *);
631
                        if (i > 0 && i <= tp->t_maxseg)
632
                                tp->t_maxseg = i;
633
                        else
634
                                error = EINVAL;
635
                        break;
636
 
637
#ifdef TCP_SACK
638
                case TCP_SACK_DISABLE:
639
                        if (m == NULL || m->m_len < sizeof (int)) {
640
                                error = EINVAL;
641
                                break;
642
                        }
643
 
644
                        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
645
                                error = EPERM;
646
                                break;
647
                        }
648
 
649
                        if (tp->t_flags & TF_SIGNATURE) {
650
                                error = EPERM;
651
                                break;
652
                        }
653
 
654
                        if (*mtod(m, int *))
655
                                tp->sack_disable = 1;
656
                        else
657
                                tp->sack_disable = 0;
658
                        break;
659
#endif
660
#ifdef TCP_SIGNATURE
661
                case TCP_SIGNATURE_ENABLE:
662
                        if (m == NULL || m->m_len < sizeof (int)) {
663
                                error = EINVAL;
664
                                break;
665
                        }
666
 
667
                        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
668
                                error = EPERM;
669
                                break;
670
                        }
671
 
672
                        if (*mtod(m, int *)) {
673
                                tp->t_flags |= TF_SIGNATURE;
674
#ifdef TCP_SACK
675
                                tp->sack_disable = 1;
676
#endif /* TCP_SACK */
677
                        } else
678
                                tp->t_flags &= ~TF_SIGNATURE;
679
                        break;
680
#endif /* TCP_SIGNATURE */
681
                default:
682
                        error = ENOPROTOOPT;
683
                        break;
684
                }
685
                if (m)
686
                        (void) m_free(m);
687
                break;
688
 
689
        case PRCO_GETOPT:
690
                *mp = m = m_get(M_WAIT, MT_SOOPTS);
691
                m->m_len = sizeof(int);
692
 
693
                switch (optname) {
694
                case TCP_NODELAY:
695
                        *mtod(m, int *) = tp->t_flags & TF_NODELAY;
696
                        break;
697
                case TCP_MAXSEG:
698
                        *mtod(m, int *) = tp->t_maxseg;
699
                        break;
700
#ifdef TCP_SACK
701
                case TCP_SACK_DISABLE:
702
                        *mtod(m, int *) = tp->sack_disable;
703
                        break;
704
#endif
705
                default:
706
                        error = ENOPROTOOPT;
707
                        break;
708
                }
709
                break;
710
        }
711
        splx(s);
712
        return (error);
713
}
714
 
715
#ifndef TCP_SENDSPACE
716
#define TCP_SENDSPACE   1024*16;
717
#endif
718
u_int   tcp_sendspace = TCP_SENDSPACE;
719
#ifndef TCP_RECVSPACE
720
#define TCP_RECVSPACE   1024*16;
721
#endif
722
u_int   tcp_recvspace = TCP_RECVSPACE;
723
 
724
/*
725
 * Attach TCP protocol to socket, allocating
726
 * internet protocol control block, tcp control block,
727
 * bufer space, and entering LISTEN state if to accept connections.
728
 */
729
int
730
tcp_attach(so)
731
        struct socket *so;
732
{
733
        register struct tcpcb *tp;
734
        struct inpcb *inp;
735
        int error;
736
 
737
        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
738
                error = soreserve(so, tcp_sendspace, tcp_recvspace);
739
                if (error)
740
                        return (error);
741
        }
742
        error = in_pcballoc(so, &tcbtable);
743
        if (error)
744
                return (error);
745
        inp = sotoinpcb(so);
746
        tp = tcp_newtcpcb(inp);
747
        if (tp == NULL) {
748
                int nofd = so->so_state & SS_NOFDREF;   /* XXX */
749
 
750
                so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
751
                in_pcbdetach(inp);
752
                so->so_state |= nofd;
753
                return (ENOBUFS);
754
        }
755
        tp->t_state = TCPS_CLOSED;
756
        return (0);
757
}
758
 
759
/*
760
 * Initiate (or continue) disconnect.
761
 * If embryonic state, just send reset (once).
762
 * If in ``let data drain'' option and linger null, just drop.
763
 * Otherwise (hard), mark socket disconnecting and drop
764
 * current input data; switch states based on user close, and
765
 * send segment to peer (with FIN).
766
 */
767
struct tcpcb *
768
tcp_disconnect(tp)
769
        register struct tcpcb *tp;
770
{
771
        struct socket *so = tp->t_inpcb->inp_socket;
772
 
773
        if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
774
                tp = tcp_close(tp);
775
        else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
776
                tp = tcp_drop(tp, 0);
777
        else {
778
                soisdisconnecting(so);
779
                sbflush(&so->so_rcv);
780
                tp = tcp_usrclosed(tp);
781
                if (tp)
782
                        (void) tcp_output(tp);
783
        }
784
        return (tp);
785
}
786
 
787
/*
788
 * User issued close, and wish to trail through shutdown states:
789
 * if never received SYN, just forget it.  If got a SYN from peer,
790
 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
791
 * If already got a FIN from peer, then almost done; go to LAST_ACK
792
 * state.  In all other cases, have already sent FIN to peer (e.g.
793
 * after PRU_SHUTDOWN), and just have to play tedious game waiting
794
 * for peer to send FIN or not respond to keep-alives, etc.
795
 * We can let the user exit from the close as soon as the FIN is acked.
796
 */
797
struct tcpcb *
798
tcp_usrclosed(tp)
799
        register struct tcpcb *tp;
800
{
801
 
802
        switch (tp->t_state) {
803
 
804
        case TCPS_CLOSED:
805
        case TCPS_LISTEN:
806
        case TCPS_SYN_SENT:
807
                tp->t_state = TCPS_CLOSED;
808
                tp = tcp_close(tp);
809
                break;
810
 
811
        case TCPS_SYN_RECEIVED:
812
        case TCPS_ESTABLISHED:
813
                tp->t_state = TCPS_FIN_WAIT_1;
814
                break;
815
 
816
        case TCPS_CLOSE_WAIT:
817
                tp->t_state = TCPS_LAST_ACK;
818
                break;
819
        }
820
        if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
821
                soisdisconnected(tp->t_inpcb->inp_socket);
822
                /*
823
                 * If we are in FIN_WAIT_2, we arrived here because the
824
                 * application did a shutdown of the send side.  Like the
825
                 * case of a transition from FIN_WAIT_1 to FIN_WAIT_2 after
826
                 * a full close, we start a timer to make sure sockets are
827
                 * not left in FIN_WAIT_2 forever.
828
                 */
829
                if (tp->t_state == TCPS_FIN_WAIT_2)
830
                        tp->t_timer[TCPT_2MSL] = tcp_maxidle;
831
        }
832
        return (tp);
833
}
834
 
835
/*
836
 * Look up a socket for ident..
837
 */
838
int
839
tcp_ident(oldp, oldlenp, newp, newlen)
840
        void *oldp;
841
        size_t *oldlenp;
842
        void *newp;
843
        size_t newlen;
844
{
845
        int error = 0, s;
846
        struct tcp_ident_mapping tir;
847
        struct inpcb *inp;
848
        struct sockaddr_in *fin, *lin;
849
 
850
        if (oldp == NULL || newp != NULL || newlen != 0)
851
                return (EINVAL);
852
        if  (*oldlenp < sizeof(tir))
853
                return (ENOMEM);
854
        if ((error = copyin(oldp, &tir, sizeof (tir))) != 0 )
855
                return (error);
856
        if (tir.faddr.sa_len != sizeof (struct sockaddr) ||
857
            tir.faddr.sa_family != AF_INET)
858
                return (EINVAL);
859
        fin = (struct sockaddr_in *)&tir.faddr;
860
        lin = (struct sockaddr_in *)&tir.laddr;
861
 
862
        s = splsoftnet();
863
        inp = in_pcbhashlookup(&tcbtable,  fin->sin_addr, fin->sin_port,
864
            lin->sin_addr, lin->sin_port);
865
        if (inp == NULL) {
866
                ++tcpstat.tcps_pcbhashmiss;
867
                inp = in_pcblookup(&tcbtable, &fin->sin_addr, fin->sin_port,
868
                    &lin->sin_addr, lin->sin_port, 0);
869
        }
870
        if (inp != NULL && (inp->inp_socket->so_state & SS_CONNECTOUT)) {
871
                tir.ruid = inp->inp_socket->so_ruid;
872
                tir.euid = inp->inp_socket->so_euid;
873
        } else {
874
                tir.ruid = -1;
875
                tir.euid = -1;
876
        }
877
        splx(s);
878
 
879
        *oldlenp = sizeof (tir);
880
        error = copyout((void *)&tir, oldp, sizeof (tir));
881
        return (error);
882
}
883
 
884
#ifdef CYGPKG_NET_SYSCTL
885
/*
886
 * Sysctl for tcp variables.
887
 */
888
int
889
tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
890
        int *name;
891
        u_int namelen;
892
        void *oldp;
893
        size_t *oldlenp;
894
        void *newp;
895
        size_t newlen;
896
{
897
 
898
        /* All sysctl names at this level are terminal. */
899
        if (namelen != 1)
900
                return (ENOTDIR);
901
 
902
        switch (name[0]) {
903
        case TCPCTL_RFC1323:
904
                return (sysctl_int(oldp, oldlenp, newp, newlen,
905
                    &tcp_do_rfc1323));
906
#ifdef TCP_SACK
907
        case TCPCTL_SACK:
908
                return (sysctl_int(oldp, oldlenp, newp, newlen,
909
                    &tcp_do_sack));
910
#endif
911
        case TCPCTL_MSSDFLT:
912
                return (sysctl_int(oldp, oldlenp, newp, newlen,
913
                    &tcp_mssdflt));
914
        case TCPCTL_KEEPINITTIME:
915
                return (sysctl_int(oldp, oldlenp, newp, newlen,
916
                    &tcptv_keep_init));
917
 
918
        case TCPCTL_KEEPIDLE:
919
                return (sysctl_int(oldp, oldlenp, newp, newlen,
920
                    &tcp_keepidle));
921
 
922
        case TCPCTL_KEEPINTVL:
923
                return (sysctl_int(oldp, oldlenp, newp, newlen,
924
                    &tcp_keepintvl));
925
 
926
        case TCPCTL_SLOWHZ:
927
                return (sysctl_rdint(oldp, oldlenp, newp, PR_SLOWHZ));
928
 
929
        case TCPCTL_BADDYNAMIC:
930
                return (sysctl_struct(oldp, oldlenp, newp, newlen,
931
                    baddynamicports.tcp, sizeof(baddynamicports.tcp)));
932
 
933
        case TCPCTL_RECVSPACE:
934
                return (sysctl_int(oldp, oldlenp, newp, newlen,&tcp_recvspace));
935
 
936
        case TCPCTL_SENDSPACE:
937
                return (sysctl_int(oldp, oldlenp, newp, newlen,&tcp_sendspace));
938
        case TCPCTL_IDENT:
939
                return (tcp_ident(oldp, oldlenp, newp, newlen));
940
        default:
941
                return (ENOPROTOOPT);
942
        }
943
        /* NOTREACHED */
944
}
945
#endif // CYGPKG_NET_SYSCTL

powered by: WebSVN 2.1.0

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