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