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