1 /* tcp_usrreq.c 1.39 81/12/03 */ 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 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 COUNT(TCP_USRREQ); 40 41 /* 42 * Make sure attached. If not, 43 * only PRU_ATTACH is valid. 44 */ 45 if (inp == 0 && req != PRU_ATTACH) { 46 splx(s); 47 return (EINVAL); 48 } 49 if (inp) { 50 tp = intotcpcb(inp); 51 #ifdef KPROF 52 tcp_acounts[tp->t_state][req]++; 53 #endif 54 } 55 switch (req) { 56 57 case PRU_ATTACH: 58 if (inp) { 59 error = EISCONN; 60 break; 61 } 62 error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 63 if (error) 64 break; 65 inp = (struct inpcb *)so->so_pcb; 66 if (so->so_options & SO_ACCEPTCONN) { 67 tp = tcp_newtcpcb(inp); 68 if (tp == 0) { 69 in_pcbdetach(inp); 70 error = ENOBUFS; 71 break; 72 } 73 tp->t_state = TCPS_LISTEN; 74 } else 75 tp->t_state = TCPS_CLOSED; 76 break; 77 78 case PRU_DETACH: 79 in_pcbdetach(inp); 80 break; 81 82 case PRU_CONNECT: 83 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 84 if (error) 85 break; 86 tp = tcp_newtcpcb(inp); 87 if (tp == 0) { 88 in_pcbdisconnect(inp); 89 error = ENOBUFS; 90 break; 91 } 92 tp->t_template = tcp_template(tp); 93 tp->t_inpcb = inp; 94 inp->inp_ppcb = (caddr_t)tp; 95 soisconnecting(so); 96 tp->t_state = TCPS_SYN_SENT; 97 (void) tcp_output(tp); 98 break; 99 100 case PRU_ACCEPT: 101 soisconnected(so); 102 break; 103 104 case PRU_DISCONNECT: 105 if (tp->t_state < TCPS_ESTABLISHED) 106 tcp_close(tp); 107 else { 108 soisdisconnecting(so); 109 (void) tcp_output(tp); 110 } 111 break; 112 113 case PRU_SHUTDOWN: 114 socantsendmore(so); 115 switch (tp->t_state) { 116 117 case TCPS_LISTEN: 118 case TCPS_SYN_SENT: 119 tp->t_state = TCPS_CLOSED; 120 break; 121 122 case TCPS_SYN_RECEIVED: 123 case TCPS_ESTABLISHED: 124 tp->t_state = TCPS_FIN_WAIT_1; 125 (void) tcp_output(tp); 126 break; 127 128 case TCPS_CLOSE_WAIT: 129 tp->t_state = TCPS_LAST_ACK; 130 (void) tcp_output(tp); 131 break; 132 } 133 break; 134 135 case PRU_RCVD: 136 (void) tcp_output(tp); 137 break; 138 139 case PRU_SEND: 140 sbappend(&so->so_snd, m); 141 /* 142 if (tp->t_flags & TF_PUSH) 143 tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 144 */ 145 if (tp->t_flags & TF_URG) 146 tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 147 (void) tcp_output(tp); 148 break; 149 150 case PRU_ABORT: 151 tcp_drop(tp, ECONNABORTED); 152 break; 153 154 case PRU_CONTROL: 155 error = EOPNOTSUPP; 156 break; 157 158 case PRU_SENSE: 159 error = EOPNOTSUPP; 160 break; 161 162 case PRU_RCVOOB: 163 error = EOPNOTSUPP; 164 break; 165 166 case PRU_SENDOOB: 167 error = EOPNOTSUPP; 168 break; 169 170 case PRU_SLOWTIMO: 171 tcp_timers(tp, (int)addr); 172 break; 173 174 default: 175 panic("tcp_usrreq"); 176 } 177 splx(s); 178 return (error); 179 } 180