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