Deleted Added
full compact
tcp_usrreq.c (14546) tcp_usrreq.c (17096)
1/*
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

--- 17 unchanged lines hidden (view full) ---

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
1/*
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

--- 17 unchanged lines hidden (view full) ---

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.21 1995/12/06 23:37:42 bde Exp $
34 * $Id: tcp_usrreq.c,v 1.22 1996/03/11 15:13:37 davidg Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/sysctl.h>
42#include <sys/malloc.h>

--- 29 unchanged lines hidden (view full) ---

72extern char *tcpstates[];
73
74static int tcp_attach __P((struct socket *));
75static int tcp_connect __P((struct tcpcb *, struct mbuf *));
76static struct tcpcb *
77 tcp_disconnect __P((struct tcpcb *));
78static struct tcpcb *
79 tcp_usrclosed __P((struct tcpcb *));
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/sysctl.h>
42#include <sys/malloc.h>

--- 29 unchanged lines hidden (view full) ---

72extern char *tcpstates[];
73
74static int tcp_attach __P((struct socket *));
75static int tcp_connect __P((struct tcpcb *, struct mbuf *));
76static struct tcpcb *
77 tcp_disconnect __P((struct tcpcb *));
78static struct tcpcb *
79 tcp_usrclosed __P((struct tcpcb *));
80
81#ifdef notdef
80/*
81 * Process a TCP user request for TCP tb. If this is a send request
82 * then m is the mbuf chain of send data. If this is a timer expiration
83 * (called from the software clock routine), then timertype tells which timer.
84 */
85/*ARGSUSED*/
86int
87tcp_usrreq(so, req, m, nam, control)

--- 298 unchanged lines hidden (view full) ---

386 }
387#ifdef TCPDEBUG
388 if (tp && (so->so_options & SO_DEBUG))
389 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
390#endif
391 splx(s);
392 return (error);
393}
82/*
83 * Process a TCP user request for TCP tb. If this is a send request
84 * then m is the mbuf chain of send data. If this is a timer expiration
85 * (called from the software clock routine), then timertype tells which timer.
86 */
87/*ARGSUSED*/
88int
89tcp_usrreq(so, req, m, nam, control)

--- 298 unchanged lines hidden (view full) ---

388 }
389#ifdef TCPDEBUG
390 if (tp && (so->so_options & SO_DEBUG))
391 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
392#endif
393 splx(s);
394 return (error);
395}
396#endif
394
397
398#ifdef TCPDEBUG
399#define TCPDEBUG0 int ostate
400#define TCPDEBUG1() ostate = tp ? tp->t_state : 0
401#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) && \
402 tcp_trace(TA_USER, ostate, tp, 0, req)
403#else
404#define TCPDEBUG0
405#define TCPDEBUG1()
406#define TCPDEBUG2(req)
407#endif
408
395/*
409/*
410 * TCP attaches to socket via pru_attach(), reserving space,
411 * and an internet control block.
412 */
413static int
414tcp_usr_attach(struct socket *so, int proto)
415{
416 int s = splnet();
417 int error;
418 struct inpcb *inp = sotoinpcb(so);
419 struct tcpcb *tp = 0;
420 TCPDEBUG0;
421
422 TCPDEBUG1();
423 if (inp) {
424 error = EISCONN;
425 goto out;
426 }
427
428 error = tcp_attach(so);
429 if (error)
430 goto out;
431
432 if ((so->so_options & SO_LINGER) && so->so_linger == 0)
433 so->so_linger = TCP_LINGERTIME * hz;
434 tp = sototcpcb(so);
435out:
436 TCPDEBUG2(PRU_ATTACH);
437 splx(s);
438 return error;
439}
440
441/*
442 * pru_detach() detaches the TCP protocol from the socket.
443 * If the protocol state is non-embryonic, then can't
444 * do this directly: have to initiate a pru_disconnect(),
445 * which may finish later; embryonic TCB's can just
446 * be discarded here.
447 */
448static int
449tcp_usr_detach(struct socket *so)
450{
451 int s = splnet();
452 int error = 0;
453 struct inpcb *inp = sotoinpcb(so);
454 struct tcpcb *tp;
455 TCPDEBUG0;
456
457 if (inp == 0) {
458 splx(s);
459 return EINVAL; /* XXX */
460 }
461 tp = intotcpcb(inp);
462 TCPDEBUG1();
463 if (tp->t_state > TCPS_LISTEN)
464 tp = tcp_disconnect(tp);
465 else
466 tp = tcp_close(tp);
467
468 TCPDEBUG2(PRU_DETACH);
469 splx(s);
470 return error;
471}
472
473#define COMMON_START() TCPDEBUG0; \
474 do { \
475 if (inp == 0) { \
476 splx(s); \
477 return EINVAL; \
478 } \
479 tp = intotcpcb(inp); \
480 TCPDEBUG1(); \
481 } while(0)
482
483#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out
484
485
486/*
487 * Give the socket an address.
488 */
489static int
490tcp_usr_bind(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 struct sockaddr_in *sinp;
497
498 COMMON_START();
499
500 /*
501 * Must check for multicast addresses and disallow binding
502 * to them.
503 */
504 sinp = mtod(nam, struct sockaddr_in *);
505 if (sinp->sin_family == AF_INET &&
506 IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
507 error = EAFNOSUPPORT;
508 goto out;
509 }
510 error = in_pcbbind(inp, nam);
511 if (error)
512 goto out;
513 COMMON_END(PRU_BIND);
514
515}
516
517/*
518 * Prepare to accept connections.
519 */
520static int
521tcp_usr_listen(struct socket *so)
522{
523 int s = splnet();
524 int error = 0;
525 struct inpcb *inp = sotoinpcb(so);
526 struct tcpcb *tp;
527
528 COMMON_START();
529 if (inp->inp_lport == 0)
530 error = in_pcbbind(inp, NULL);
531 if (error == 0)
532 tp->t_state = TCPS_LISTEN;
533 COMMON_END(PRU_LISTEN);
534}
535
536/*
537 * Initiate connection to peer.
538 * Create a template for use in transmissions on this connection.
539 * Enter SYN_SENT state, and mark socket as connecting.
540 * Start keep-alive timer, and seed output sequence space.
541 * Send initial segment on connection.
542 */
543static int
544tcp_usr_connect(struct socket *so, struct mbuf *nam)
545{
546 int s = splnet();
547 int error = 0;
548 struct inpcb *inp = sotoinpcb(so);
549 struct tcpcb *tp;
550 struct sockaddr_in *sinp;
551
552 COMMON_START();
553
554 /*
555 * Must disallow TCP ``connections'' to multicast addresses.
556 */
557 sinp = mtod(nam, struct sockaddr_in *);
558 if (sinp->sin_family == AF_INET
559 && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
560 error = EAFNOSUPPORT;
561 goto out;
562 }
563
564 if ((error = tcp_connect(tp, nam)) != 0)
565 goto out;
566 error = tcp_output(tp);
567 COMMON_END(PRU_CONNECT);
568}
569
570/*
571 * Initiate disconnect from peer.
572 * If connection never passed embryonic stage, just drop;
573 * else if don't need to let data drain, then can just drop anyways,
574 * else have to begin TCP shutdown process: mark socket disconnecting,
575 * drain unread data, state switch to reflect user close, and
576 * send segment (e.g. FIN) to peer. Socket will be really disconnected
577 * when peer sends FIN and acks ours.
578 *
579 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
580 */
581static int
582tcp_usr_disconnect(struct socket *so)
583{
584 int s = splnet();
585 int error = 0;
586 struct inpcb *inp = sotoinpcb(so);
587 struct tcpcb *tp;
588
589 COMMON_START();
590 tp = tcp_disconnect(tp);
591 COMMON_END(PRU_DISCONNECT);
592}
593
594/*
595 * Accept a connection. Essentially all the work is
596 * done at higher levels; just return the address
597 * of the peer, storing through addr.
598 */
599static int
600tcp_usr_accept(struct socket *so, struct mbuf *nam)
601{
602 int s = splnet();
603 int error = 0;
604 struct inpcb *inp = sotoinpcb(so);
605 struct tcpcb *tp;
606
607 COMMON_START();
608 in_setpeeraddr(inp, nam);
609 COMMON_END(PRU_ACCEPT);
610}
611
612/*
613 * Mark the connection as being incapable of further output.
614 */
615static int
616tcp_usr_shutdown(struct socket *so)
617{
618 int s = splnet();
619 int error = 0;
620 struct inpcb *inp = sotoinpcb(so);
621 struct tcpcb *tp;
622
623 COMMON_START();
624 socantsendmore(so);
625 tp = tcp_usrclosed(tp);
626 if (tp)
627 error = tcp_output(tp);
628 COMMON_END(PRU_SHUTDOWN);
629}
630
631/*
632 * After a receive, possibly send window update to peer.
633 */
634static int
635tcp_usr_rcvd(struct socket *so, int flags)
636{
637 int s = splnet();
638 int error = 0;
639 struct inpcb *inp = sotoinpcb(so);
640 struct tcpcb *tp;
641
642 COMMON_START();
643 tcp_output(tp);
644 COMMON_END(PRU_RCVD);
645}
646
647/*
648 * Do a send by putting data in output queue and updating urgent
649 * marker if URG set. Possibly send more data.
650 */
651static int
652tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
653 struct mbuf *control)
654{
655 int s = splnet();
656 int error = 0;
657 struct inpcb *inp = sotoinpcb(so);
658 struct tcpcb *tp;
659
660 COMMON_START();
661 if (control && control->m_len) {
662 m_freem(control); /* XXX shouldn't caller do this??? */
663 if (m)
664 m_freem(m);
665 return EINVAL;
666 }
667
668 if(!(flags & PRUS_OOB)) {
669 sbappend(&so->so_snd, m);
670 if (nam && tp->t_state < TCPS_SYN_SENT) {
671 /*
672 * Do implied connect if not yet connected,
673 * initialize window to default value, and
674 * initialize maxseg/maxopd using peer's cached
675 * MSS.
676 */
677 error = tcp_connect(tp, nam);
678 if (error)
679 goto out;
680 tp->snd_wnd = TTCP_CLIENT_SND_WND;
681 tcp_mss(tp, -1);
682 }
683
684 if (flags & PRUS_EOF) {
685 /*
686 * Close the send side of the connection after
687 * the data is sent.
688 */
689 socantsendmore(so);
690 tp = tcp_usrclosed(tp);
691 }
692 if (tp != NULL)
693 error = tcp_output(tp);
694 } else {
695 if (sbspace(&so->so_snd) < -512) {
696 m_freem(m);
697 error = ENOBUFS;
698 goto out;
699 }
700 /*
701 * According to RFC961 (Assigned Protocols),
702 * the urgent pointer points to the last octet
703 * of urgent data. We continue, however,
704 * to consider it to indicate the first octet
705 * of data past the urgent section.
706 * Otherwise, snd_up should be one lower.
707 */
708 sbappend(&so->so_snd, m);
709 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
710 tp->t_force = 1;
711 error = tcp_output(tp);
712 tp->t_force = 0;
713 }
714 COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB :
715 ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
716}
717
718/*
719 * Abort the TCP.
720 */
721static int
722tcp_usr_abort(struct socket *so)
723{
724 int s = splnet();
725 int error = 0;
726 struct inpcb *inp = sotoinpcb(so);
727 struct tcpcb *tp;
728
729 COMMON_START();
730 tp = tcp_drop(tp, ECONNABORTED);
731 COMMON_END(PRU_ABORT);
732}
733
734/*
735 * Fill in st_bklsize for fstat() operations on a socket.
736 */
737static int
738tcp_usr_sense(struct socket *so, struct stat *sb)
739{
740 int s = splnet();
741
742 sb->st_blksize = so->so_snd.sb_hiwat;
743 splx(s);
744 return 0;
745}
746
747/*
748 * Receive out-of-band data.
749 */
750static int
751tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
752{
753 int s = splnet();
754 int error = 0;
755 struct inpcb *inp = sotoinpcb(so);
756 struct tcpcb *tp;
757
758 COMMON_START();
759 if ((so->so_oobmark == 0 &&
760 (so->so_state & SS_RCVATMARK) == 0) ||
761 so->so_options & SO_OOBINLINE ||
762 tp->t_oobflags & TCPOOB_HADDATA) {
763 error = EINVAL;
764 goto out;
765 }
766 if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
767 error = EWOULDBLOCK;
768 goto out;
769 }
770 m->m_len = 1;
771 *mtod(m, caddr_t) = tp->t_iobc;
772 if ((flags & MSG_PEEK) == 0)
773 tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
774 COMMON_END(PRU_RCVOOB);
775}
776
777static int
778tcp_usr_sockaddr(struct socket *so, struct mbuf *nam)
779{
780 int s = splnet();
781 int error = 0;
782 struct inpcb *inp = sotoinpcb(so);
783 struct tcpcb *tp;
784
785 COMMON_START();
786 in_setsockaddr(inp, nam);
787 COMMON_END(PRU_SOCKADDR);
788}
789
790static int
791tcp_usr_peeraddr(struct socket *so, struct mbuf *nam)
792{
793 int s = splnet();
794 int error = 0;
795 struct inpcb *inp = sotoinpcb(so);
796 struct tcpcb *tp;
797
798 COMMON_START();
799 in_setpeeraddr(inp, nam);
800 COMMON_END(PRU_PEERADDR);
801}
802
803/*
804 * XXX - this should just be a call to in_control, but we need to get
805 * the types worked out.
806 */
807static int
808tcp_usr_control(struct socket *so, int cmd, caddr_t arg, struct ifnet *ifp)
809{
810 return in_control(so, cmd, arg, ifp);
811}
812
813/* xxx - should be const */
814struct pr_usrreqs tcp_usrreqs = {
815 tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
816 tcp_usr_connect, pru_connect2_notsupp, tcp_usr_control, tcp_usr_detach,
817 tcp_usr_disconnect, tcp_usr_listen, tcp_usr_peeraddr, tcp_usr_rcvd,
818 tcp_usr_rcvoob, tcp_usr_send, tcp_usr_sense, tcp_usr_shutdown,
819 tcp_usr_sockaddr
820};
821
822/*
396 * Common subroutine to open a TCP connection to remote host specified
397 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
398 * port number if needed. Call in_pcbladdr to do the routing and to choose
399 * a local host address (interface). If there is an existing incarnation
400 * of the same connection in TIME-WAIT state and if the remote host was
401 * sending CC options and if the connection duration was < MSL, then
402 * truncate the previous TIME-WAIT state and proceed.
403 * Initialize connection parameters and enter SYN-SENT state.

--- 311 unchanged lines hidden ---
823 * Common subroutine to open a TCP connection to remote host specified
824 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
825 * port number if needed. Call in_pcbladdr to do the routing and to choose
826 * a local host address (interface). If there is an existing incarnation
827 * of the same connection in TIME-WAIT state and if the remote host was
828 * sending CC options and if the connection duration was < MSL, then
829 * truncate the previous TIME-WAIT state and proceed.
830 * Initialize connection parameters and enter SYN-SENT state.

--- 311 unchanged lines hidden ---