1 /* tcp_usrreq.c 1.44 81/12/20 */ 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 "../net/tcp_debug.h" 22 #include "../errno.h" 23 24 extern char *tcpstates[]; 25 struct tcpcb *tcp_newtcpcb(); 26 /* 27 * Process a TCP user request for tcp tb. If this is a send request 28 * then m is the mbuf chain of send data. If this is a timer expiration 29 * (called from the software clock routine), then timertype tells which timer. 30 */ 31 tcp_usrreq(so, req, m, addr) 32 struct socket *so; 33 int req; 34 struct mbuf *m; 35 caddr_t addr; 36 { 37 register struct inpcb *inp = sotoinpcb(so); 38 register struct tcpcb *tp; 39 int s = splnet(); 40 int error = 0; 41 int ostate; 42 COUNT(TCP_USRREQ); 43 44 /* 45 * Make sure attached. If not, 46 * only PRU_ATTACH is valid. 47 */ 48 if (inp == 0 && req != PRU_ATTACH) { 49 splx(s); 50 return (EINVAL); 51 } 52 if (inp) { 53 tp = intotcpcb(inp); 54 #ifdef KPROF 55 tcp_acounts[tp->t_state][req]++; 56 #endif 57 ostate = tp->t_state; 58 } 59 switch (req) { 60 61 case PRU_ATTACH: 62 if (inp) { 63 error = EISCONN; 64 break; 65 } 66 error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 67 if (error) 68 break; 69 inp = (struct inpcb *)so->so_pcb; 70 tp = tcp_newtcpcb(inp); 71 if (so->so_options & SO_ACCEPTCONN) { 72 if (tp == 0) { 73 in_pcbdetach(inp); 74 error = ENOBUFS; 75 break; 76 } 77 tp->t_state = TCPS_LISTEN; 78 } else 79 tp->t_state = TCPS_CLOSED; 80 break; 81 82 case PRU_DETACH: 83 if (tp) 84 goto disconn; 85 in_pcbdetach(inp); 86 break; 87 88 case PRU_CONNECT: 89 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 90 if (error) 91 break; 92 tp->t_template = tcp_template(tp); 93 if (tp->t_template == 0) 94 goto badcon2; 95 tp->t_inpcb = inp; 96 inp->inp_ppcb = (caddr_t)tp; 97 soisconnecting(so); 98 tp->t_state = TCPS_SYN_SENT; 99 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 100 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 101 tcp_sendseqinit(tp); 102 (void) tcp_output(tp); 103 break; 104 105 badcon2: 106 (void) m_free(dtom(tp)); 107 badcon: 108 in_pcbdisconnect(inp); 109 error = ENOBUFS; 110 break; 111 112 case PRU_ACCEPT: 113 *(struct sockaddr *)addr = so->so_addr; 114 break; 115 116 case PRU_DISCONNECT: 117 disconn: 118 if (tp->t_state < TCPS_ESTABLISHED) 119 tcp_close(tp); 120 else if ((so->so_state & SO_LETDATADRAIN) == 0) 121 tcp_drop(tp, 0); 122 else { 123 soisdisconnecting(so); 124 sbflush(&so->so_rcv); 125 tcp_usrclosed(tp); 126 (void) tcp_output(tp); 127 } 128 break; 129 130 case PRU_SHUTDOWN: 131 socantsendmore(so); 132 tcp_usrclosed(tp); 133 (void) tcp_output(tp); 134 break; 135 136 case PRU_RCVD: 137 (void) tcp_output(tp); 138 break; 139 140 case PRU_SEND: 141 sbappend(&so->so_snd, m); 142 /* 143 if (tp->t_flags & TF_PUSH) 144 tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 145 */ 146 if (tp->t_flags & TF_URG) 147 tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 148 (void) tcp_output(tp); 149 break; 150 151 case PRU_ABORT: 152 tcp_drop(tp, ECONNABORTED); 153 break; 154 155 case PRU_CONTROL: 156 error = EOPNOTSUPP; 157 break; 158 159 case PRU_SENSE: 160 error = EOPNOTSUPP; 161 break; 162 163 case PRU_RCVOOB: 164 error = EOPNOTSUPP; 165 break; 166 167 case PRU_SENDOOB: 168 error = EOPNOTSUPP; 169 break; 170 171 case PRU_SLOWTIMO: 172 tcp_timers(tp, (int)addr); 173 req |= (int)addr << 8; /* for debug's sake */ 174 break; 175 176 default: 177 panic("tcp_usrreq"); 178 } 179 if (tp && (so->so_options & SO_DEBUG)) 180 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 181 splx(s); 182 return (error); 183 } 184 185 tcp_usrclosed(tp) 186 struct tcpcb *tp; 187 { 188 189 switch (tp->t_state) { 190 191 case TCPS_LISTEN: 192 case TCPS_SYN_SENT: 193 tp->t_state = TCPS_CLOSED; 194 tcp_close(tp); 195 break; 196 197 case TCPS_SYN_RECEIVED: 198 case TCPS_ESTABLISHED: 199 tp->t_state = TCPS_FIN_WAIT_1; 200 break; 201 202 case TCPS_CLOSE_WAIT: 203 tp->t_state = TCPS_LAST_ACK; 204 break; 205 } 206 } 207