1 /* nsp_usrreq.c 1.5 82/12/18 */ 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 "../netdecnet/decnet.h" 10 #include "../netdecnet/dn_systm.h" 11 #include "../net/if.h" 12 #include "../netdecnet/nsp.h" 13 #include "../netdecnet/nsp_var.h" 14 #include <errno.h> 15 16 /* 17 * NSP protocol interface to socket abstraction. 18 */ 19 struct nspcb *nsp_newnspcb(); 20 21 /* 22 * Process an NSP user request for NSP np. If this is a send request 23 * then m is the mbuf chain of send data. If this is a timer expiration 24 * (called from the software clock routine), then timertype tells which timer. 25 */ 26 nsp_usrreq(so, req, m, addr) 27 struct socket *so; 28 int req; 29 struct mbuf *m; 30 caddr_t addr; 31 { 32 register struct nspcb *np = sotonspcb(so); 33 int s = splnet(); 34 int error = 0; 35 int ostate; 36 COUNT(NSP_USRREQ); 37 38 /* 39 * When an NSP is attached to a socket, then there will be 40 * a (struct nspcb) pointed at by the socket. 41 * The normal sequence of events is: 42 * PRU_ATTACH creating these structures 43 * PRU_CONNECT connecting to a remote peer 44 * (PRU_SEND|PRU_RCVD)* exchanging data 45 * PRU_DISCONNECT disconnecting from remote peer 46 * PRU_DETACH deleting the structures 47 * With the operations from PRU_CONNECT through PRU_DISCONNECT 48 * possible repeated several times. 49 * 50 * MULTIPLE CONNECTS ARE NOT YET IMPLEMENTED. 51 */ 52 if (np == 0 && req != PRU_ATTACH) { 53 splx(s); 54 return (EINVAL); /* XXX */ 55 } 56 if (np) { 57 ostate = np->n_state; 58 } 59 switch (req) { 60 61 /* 62 * NSP attaches to socket via PRU_ATTACH, reserving space 63 * and NSP control block. 64 **** If the socket is to receive connections, 65 **** then the LISTEN state is entered. 66 */ 67 case PRU_ATTACH: 68 if (np) { 69 error = EISCONN; 70 break; 71 } 72 error = nsp_attach(so, (struct sockaddr *)addr); 73 if (error) 74 break; 75 np = sotonspcb(so); 76 break; 77 78 /* 79 * PRU_DETACH detaches the NSP protocol from the socket. 80 * If the protocol state is non-embryonic, then can't 81 * do this directly: have to initiate a PRU_DISCONNECT, 82 * which may finish later; embryonic nspcb's can just 83 * be discarded here. 84 */ 85 case PRU_DETACH: 86 if (np->n_state != NS_O && np->n_state != NS_CL 87 && np->n_state != NS_LI) 88 nsp_disconnect(np, <reason>); 89 else { 90 nsp_close(np); 91 np = 0; 92 } 93 break; 94 95 /* 96 * Initiate connection to peer. 97 * Enter CI state, and mark socket as connecting. 98 **** Start keep-alive timer, and seed output sequence space. 99 **** Send initial segment on connection. 100 */ 101 case PRU_CONNECT: 102 error = dn_pcbconnect(np, (struct sockaddr_dn *)addr); 103 if (error) 104 break; 105 soisconnecting(so); 106 nsp_connect(np); 107 break; 108 109 /* 110 * Initiate disconnect from peer. 111 * If connection never passed embryonic stage, just drop; 112 * else if don't need to let data drain, then can just drop anyways, 113 * else have to begin NSP shutdown process: mark socket disconnecting, 114 * drain unread data, state switch to reflect user close, and 115 * send segment (e.g. DI) to peer. Socket will be really disconnected 116 * when peer sends DC to ack our DI. 117 * 118 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC NSPCB. 119 */ 120 case PRU_DISCONNECT: 121 nsp_disconnect(np); 122 break; 123 124 /* 125 * Accept a connection. Essentially all the work is 126 * done at higher levels; just return the address 127 * of the peer, storing through addr. 128 */ 129 case PRU_ACCEPT: 130 dn_pcbconnaddr(np, (struct sockaddr *)addr); 131 break; 132 133 /*** BEGIN NOT MODIFIED FOR NSP ***/ 134 /* 135 * Mark the connection as being incapable of further output. 136 */ 137 case PRU_SHUTDOWN: 138 socantsendmore(so); 139 nsp_usrclosed(np); 140 (void) nsp_output(np); 141 break; 142 143 /* 144 * After a receive, possibly send window update to peer. 145 */ 146 case PRU_RCVD: 147 (void) nsp_output(np); 148 break; 149 /*** END NOT MODIFIED FOR NSP ***/ 150 151 /* 152 * Do a send by putting data in output queue and 153 * calling output processor. 154 */ 155 case PRU_SEND: 156 sbpappend(&so->so_snd, m); 157 (void) nsp_output(np); 158 break; 159 160 /*** BEGIN NOT MODIFIED FOR NSP ***/ 161 /* 162 * Abort the NSP. 163 */ 164 case PRU_ABORT: 165 nsp_drop(np, ECONNABORTED); 166 break; 167 168 /* SOME AS YET UNIMPLEMENTED HOOKS */ 169 case PRU_CONTROL: 170 error = EOPNOTSUPP; 171 break; 172 173 case PRU_SENSE: 174 error = EOPNOTSUPP; 175 break; 176 /* END UNIMPLEMENTED HOOKS */ 177 178 case PRU_RCVOOB: 179 if (so->so_oobmark == 0 && 180 (so->so_state & SS_RCVATMARK) == 0) { 181 error = EINVAL; 182 break; 183 } 184 if ((np->n_flags & NSP_RCVINTR) == 0) { 185 error = EWOULDBLOCK; 186 break; 187 } 188 /* RETURN THE DATA */ 189 break; 190 191 case PRU_SENDOOB: 192 /* 193 if interrupt data present return error (can't queue) 194 if len > 16 return error 195 put in xmt mbuf 196 mark interrupt data available 197 call nsp_output 198 */ 199 break; 200 201 /* 202 * NSP slow timer went off; going through this 203 * routine for tracing's sake. 204 */ 205 case PRU_SLOWTIMO: 206 nsp_timers(np, (int)addr); 207 req |= (int)addr << 8; /* for debug's sake */ 208 break; 209 /*** END NOT MODIFIED FOR NSP ***/ 210 211 default: 212 panic("nsp_usrreq"); 213 } 214 if (np && (so->so_options & SO_DEBUG)) 215 nsp_trace(NA_USER, ostate, np, (struct XXXXXXXX *)0, req); 216 splx(s); 217 return (error); 218 } 219 220 /* 221 * Attach NSP protocol to socket, allocating NSP control block, 222 * bufer space, and entering LISTEN state if to accept connections. 223 */ 224 nsp_attach(so, sa) 225 struct socket *so; 226 struct sockaddr *sa; 227 { 228 register struct nspcb *np; 229 struct sockaddr_dn *sdn = (struct sockaddr_dn *)sa; 230 struct mbuf *m; 231 int error; 232 233 if (sdn) { 234 if (sdn->sdn_family != AF_DECNET) 235 return (EAFNOSUPPORT); 236 /* the user has specified a sockaddr with a socreate. 237 all this can do is allow the user to specify an object 238 type or other info if he is going to wait for a connection. 239 figure this out later. */ 240 } else { 241 /* nothing specified, will expect a connect request soon */ 242 } 243 m = m_getclr(MT_CANTWAIT, MT_PCB); 244 if (m == 0) 245 return (ENOBUFS); 246 if (sbreserve(&so->so_snd, 1024) == 0) { 247 bad: 248 (void) m_free(m); 249 return (ENOBUFS); 250 } 251 if (sbreserve(&so->so_rcv, 1024) == 0) { 252 sbrelease(&so->so_snd); 253 goto bad; 254 } 255 np = mtod(m, struct nspcb *); 256 np->n_head = &ncb; 257 insque(np, &ncb); 258 sp->so_pcb = (caddr_t)np; 259 sdn = (struct sockaddr_dn *)&so->so_addr; 260 sdn->sdn_family == AF_DECNET; 261 sdn->sdn_addr = WHAT ELSE NEEDS TO BE FILLED IN HERE? 262 if (so->so_options & SO_ACCEPTCONN) { 263 np->n_state = NS_LI; 264 } else 265 np->n_state = NS_O; 266 return (0); 267 } 268 269 /*** BEGIN NOT MODIFIED FOR NSP ***/ 270 /* 271 * Initiate (or continue) disconnect. 272 * If embryonic state, just send reset (once). 273 * If not in ``let data drain'' option, just drop. 274 * Otherwise (hard), mark socket disconnecting and drop 275 * current input data; switch states based on user close, and 276 * send segment to peer (with FIN). 277 */ 278 nsp_disconnect(np) 279 struct nspcb *np; 280 { 281 struct socket *so = np->n_socket; 282 283 if (np->n_state < NSPS_ESTABLISHED) 284 nsp_close(np); 285 else if (so->so_linger == 0) 286 nsp_drop(np, 0); 287 else { 288 soisdisconnecting(so); 289 sbflush(&so->so_rcv); 290 nsp_usrclosed(np); 291 (void) nsp_output(np); 292 } 293 } 294 295 /* 296 * User issued close, and wish to trail through shutdown states: 297 * if never received SYN, just forget it. If got a SYN from peer, 298 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 299 * If already got a FIN from peer, then almost done; go to LAST_ACK 300 * state. In all other cases, have already sent FIN to peer (e.g. 301 * after PRU_SHUTDOWN), and just have to play tedious game waiting 302 * for peer to send FIN or not respond to keep-alives, etc. 303 */ 304 nsp_usrclosed(np) 305 struct nspcb *np; 306 { 307 308 switch (np->n_state) { 309 310 case NSPS_LISTEN: 311 case NSPS_SYN_SENT: 312 np->n_state = NSPS_CLOSED; 313 nsp_close(np); 314 break; 315 316 case NSPS_SYN_RECEIVED: 317 case NSPS_ESTABLISHED: 318 np->n_state = NSPS_FIN_WAIT_1; 319 break; 320 321 case NSPS_CLOSE_WAIT: 322 np->n_state = NSPS_LAST_ACK; 323 break; 324 } 325 } 326