1 /* tcp_usrreq.c 1.36 81/11/26 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/socket.h" 7 #include "../h/socketvar.h" 8 #include "../h/protosw.h" 9 #include "../net/in.h" 10 #include "../net/in_pcb.h" 11 #include "../net/in_systm.h" 12 #include "../net/if.h" 13 #include "../net/ip.h" 14 #include "../net/ip_var.h" 15 #include "../net/tcp.h" 16 #include "../net/tcp_fsm.h" 17 #include "../net/tcp_seq.h" 18 #include "../net/tcp_timer.h" 19 #include "../net/tcp_var.h" 20 #include "../net/tcpip.h" 21 #include "/usr/include/errno.h" 22 23 struct tcpcb *tcp_newtcpcb(); 24 /* 25 * Process a TCP user request for tcp tb. If this is a send request 26 * then m is the mbuf chain of send data. If this is a timer expiration 27 * (called from the software clock routine), then timertype tells which timer. 28 */ 29 tcp_usrreq(so, req, m, addr) 30 struct socket *so; 31 int req; 32 struct mbuf *m; 33 caddr_t addr; 34 { 35 register struct inpcb *inp = sotoinpcb(so); 36 register struct tcpcb *tp; 37 int s = splnet(); 38 int error = 0; 39 struct tcpiphdr ti; 40 COUNT(TCP_USRREQ); 41 42 /* 43 * Make sure attached. If not, 44 * only PRU_ATTACH is valid. 45 */ 46 if (inp == 0 && req != PRU_ATTACH) { 47 splx(s); 48 return (EINVAL); 49 } 50 if (inp) { 51 tp = intotcpcb(inp); 52 #ifdef KPROF 53 tcp_acounts[tp->t_state][req]++; 54 #endif 55 } 56 switch (req) { 57 58 case PRU_ATTACH: 59 if (inp) { 60 error = EISCONN; 61 break; 62 } 63 error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 64 if (error) 65 break; 66 inp = (struct inpcb *)so->so_pcb; 67 if (so->so_options & SO_ACCEPTCONN) { 68 tp = tcp_newtcpcb(inp); 69 if (tp == 0) { 70 in_pcbfree(inp); 71 error = ENOBUFS; 72 break; 73 } 74 tp->t_state = TCPS_LISTEN; 75 } else 76 tp->t_state = TCPS_CLOSED; 77 break; 78 79 case PRU_DETACH: 80 break; 81 82 case PRU_CONNECT: 83 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 84 if (error) 85 break; 86 tp = tcp_newtcpcb(inp); 87 if (tp == 0) { 88 inp->inp_faddr.s_addr = 0; 89 error = ENOBUFS; 90 break; 91 } 92 tp->t_inpcb = inp; 93 inp->inp_ppcb = (caddr_t)tp; 94 soisconnecting(so); 95 tp->t_state = TCPS_SYN_SENT; 96 tcp_output(tp); 97 break; 98 99 case PRU_ACCEPT: 100 soisconnected(so); 101 break; 102 103 case PRU_DISCONNECT: 104 if (tp->t_state < TCPS_ESTABLISHED) 105 tcp_close(tp); 106 else { 107 soisdisconnecting(so); 108 tcp_output(tp); 109 } 110 break; 111 112 case PRU_SHUTDOWN: 113 socantsendmore(so); 114 switch (tp->t_state) { 115 116 case TCPS_LISTEN: 117 case TCPS_SYN_SENT: 118 tp->t_state = TCPS_CLOSED; 119 break; 120 121 case TCPS_SYN_RECEIVED: 122 case TCPS_ESTABLISHED: 123 tp->t_state = TCPS_FIN_WAIT_1; 124 tcp_output(tp); 125 break; 126 127 case TCPS_CLOSE_WAIT: 128 tp->t_state = TCPS_LAST_ACK; 129 tcp_output(tp); 130 break; 131 } 132 break; 133 134 case PRU_RCVD: 135 tcp_output(tp); 136 break; 137 138 case PRU_SEND: 139 sbappend(&so->so_snd, m); 140 /* 141 if (tp->t_flags & TF_PUSH) 142 tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 143 */ 144 if (tp->t_flags & TF_URG) 145 tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 146 tcp_output(tp); 147 break; 148 149 case PRU_ABORT: 150 tcp_drop(tp, ECONNABORTED); 151 break; 152 153 case PRU_CONTROL: 154 error = EOPNOTSUPP; 155 break; 156 157 case PRU_SLOWTIMO: 158 tcp_timers(tp, (int)addr); 159 break; 160 161 default: 162 panic("tcp_usrreq"); 163 } 164 splx(s); 165 return (error); 166 } 167