1 /* tcp_usrreq.c 1.42 81/12/19 */ 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 "../errno.h" 22 23 extern char *tcpstates[]; 24 struct tcpcb *tcp_newtcpcb(); 25 /* 26 * Process a TCP user request for tcp tb. If this is a send request 27 * then m is the mbuf chain of send data. If this is a timer expiration 28 * (called from the software clock routine), then timertype tells which timer. 29 */ 30 tcp_usrreq(so, req, m, addr) 31 struct socket *so; 32 int req; 33 struct mbuf *m; 34 caddr_t addr; 35 { 36 register struct inpcb *inp = sotoinpcb(so); 37 register struct tcpcb *tp; 38 int s = splnet(); 39 int error = 0; 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_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 64 if (error) 65 break; 66 inp = (struct inpcb *)so->so_pcb; 67 tp = tcp_newtcpcb(inp); 68 if (so->so_options & SO_ACCEPTCONN) { 69 if (tp == 0) { 70 in_pcbdetach(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 in_pcbdetach(inp); 81 break; 82 83 case PRU_CONNECT: 84 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 85 if (error) 86 break; 87 tp = tcp_newtcpcb(inp); 88 if (tp == 0) 89 goto badcon; 90 tp->t_template = tcp_template(tp); 91 if (tp->t_template == 0) 92 goto badcon2; 93 tp->t_inpcb = inp; 94 inp->inp_ppcb = (caddr_t)tp; 95 soisconnecting(so); 96 tp->t_state = TCPS_SYN_SENT; 97 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 98 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 99 tcp_sendseqinit(tp); 100 (void) tcp_output(tp); 101 break; 102 103 badcon2: 104 (void) m_free(dtom(tp)); 105 badcon: 106 in_pcbdisconnect(inp); 107 error = ENOBUFS; 108 break; 109 110 case PRU_ACCEPT: 111 break; 112 113 case PRU_DISCONNECT: 114 if (tp->t_state < TCPS_ESTABLISHED) 115 tcp_close(tp); 116 else { 117 soisdisconnecting(so); 118 tcp_usrclosed(tp); 119 (void) tcp_output(tp); 120 } 121 break; 122 123 case PRU_SHUTDOWN: 124 socantsendmore(so); 125 tcp_usrclosed(tp); 126 (void) tcp_output(tp); 127 break; 128 129 case PRU_RCVD: 130 (void) tcp_output(tp); 131 break; 132 133 case PRU_SEND: 134 sbappend(&so->so_snd, m); 135 /* 136 if (tp->t_flags & TF_PUSH) 137 tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 138 */ 139 if (tp->t_flags & TF_URG) 140 tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 141 (void) tcp_output(tp); 142 break; 143 144 case PRU_ABORT: 145 tcp_drop(tp, ECONNABORTED); 146 break; 147 148 case PRU_CONTROL: 149 error = EOPNOTSUPP; 150 break; 151 152 case PRU_SENSE: 153 error = EOPNOTSUPP; 154 break; 155 156 case PRU_RCVOOB: 157 error = EOPNOTSUPP; 158 break; 159 160 case PRU_SENDOOB: 161 error = EOPNOTSUPP; 162 break; 163 164 case PRU_SLOWTIMO: 165 tcp_timers(tp, (int)addr); 166 break; 167 168 default: 169 panic("tcp_usrreq"); 170 } 171 splx(s); 172 return (error); 173 } 174 175 tcp_usrclosed(tp) 176 struct tcpcb *tp; 177 { 178 179 switch (tp->t_state) { 180 181 case TCPS_LISTEN: 182 case TCPS_SYN_SENT: 183 tp->t_state = TCPS_CLOSED; 184 tcp_close(tp); 185 break; 186 187 case TCPS_SYN_RECEIVED: 188 case TCPS_ESTABLISHED: 189 tp->t_state = TCPS_FIN_WAIT_1; 190 break; 191 192 case TCPS_CLOSE_WAIT: 193 tp->t_state = TCPS_LAST_ACK; 194 break; 195 } 196 } 197