/* nsp_usrreq.c 1.3 82/10/09 */
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../netdecnet/decnet.h"
#include "../netdecnet/dn_systm.h"
#include "../netdecnet/nsp.h"
#include "../netdecnet/nsp_var.h"
* NSP protocol interface to socket abstraction.
struct nspcb
*nsp_newnspcb();
* Process an NSP user request for NSP np. If this is a send request
* then m is the mbuf chain of send data. If this is a timer expiration
* (called from the software clock routine), then timertype tells which timer.
nsp_usrreq(so
, req
, m
, addr
)
register struct nspcb
*np
= sotonspcb(so
);
* When an NSP is attached to a socket, then there will be
* a (struct nspcb) pointed at by the socket.
* The normal sequence of events is:
* PRU_ATTACH creating these structures
* PRU_CONNECT connecting to a remote peer
* (PRU_SEND|PRU_RCVD)* exchanging data
* PRU_DISCONNECT disconnecting from remote peer
* PRU_DETACH deleting the structures
* With the operations from PRU_CONNECT through PRU_DISCONNECT
* possible repeated several times.
* MULTIPLE CONNECTS ARE NOT YET IMPLEMENTED.
if (np
== 0 && req
!= PRU_ATTACH
) {
return (EINVAL
); /* XXX */
* NSP attaches to socket via PRU_ATTACH, reserving space
**** If the socket is to receive connections,
**** then the LISTEN state is entered.
error
= nsp_attach(so
, (struct sockaddr
*)addr
);
* PRU_DETACH detaches the NSP protocol from the socket.
* If the protocol state is non-embryonic, then can't
* do this directly: have to initiate a PRU_DISCONNECT,
* which may finish later; embryonic nspcb's can just
if (np
->n_state
!= NS_O
&& np
->n_state
!= NS_CL
nsp_disconnect(np
, <reason
>);
* Initiate connection to peer.
* Enter CI state, and mark socket as connecting.
**** Start keep-alive timer, and seed output sequence space.
**** Send initial segment on connection.
error
= dn_pcbconnect(np
, (struct sockaddr_dn
*)addr
);
* Initiate disconnect from peer.
* If connection never passed embryonic stage, just drop;
* else if don't need to let data drain, then can just drop anyways,
* else have to begin NSP shutdown process: mark socket disconnecting,
* drain unread data, state switch to reflect user close, and
* send segment (e.g. DI) to peer. Socket will be really disconnected
* when peer sends DC to ack our DI.
* SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC NSPCB.
* Accept a connection. Essentially all the work is
* done at higher levels; just return the address
* of the peer, storing through addr.
dn_pcbconnaddr(np
, (struct sockaddr
*)addr
);
/*** BEGIN NOT MODIFIED FOR NSP ***/
* Mark the connection as being incapable of further output.
* After a receive, possibly send window update to peer.
/*** END NOT MODIFIED FOR NSP ***/
* Do a send by putting data in output queue and
* calling output processor.
sbpappend(&so
->so_snd
, m
);
/*** BEGIN NOT MODIFIED FOR NSP ***/
nsp_drop(np
, ECONNABORTED
);
/* SOME AS YET UNIMPLEMENTED HOOKS */
/* END UNIMPLEMENTED HOOKS */
if (so
->so_oobmark
== 0 &&
(so
->so_state
& SS_RCVATMARK
) == 0) {
if ((np
->n_flags
& NSP_RCVINTR
) == 0) {
if interrupt data present return error (can't queue)
mark interrupt data available
* NSP slow timer went off; going through this
* routine for tracing's sake.
nsp_timers(np
, (int)addr
);
req
|= (int)addr
<< 8; /* for debug's sake */
/*** END NOT MODIFIED FOR NSP ***/
if (np
&& (so
->so_options
& SO_DEBUG
))
nsp_trace(NA_USER
, ostate
, np
, (struct XXXXXXXX
*)0, req
);
* Attach NSP protocol to socket, allocating NSP control block,
* bufer space, and entering LISTEN state if to accept connections.
register struct nspcb
*np
;
struct sockaddr_dn
*sdn
= (struct sockaddr_dn
*)sa
;
if (sdn
->sdn_family
!= AF_DECNET
)
/* the user has specified a sockaddr with a socreate.
all this can do is allow the user to specify an object
type or other info if he is going to wait for a connection.
figure this out later. */
/* nothing specified, will expect a connect request soon */
if (sbreserve(&so
->so_snd
, 1024) == 0) {
if (sbreserve(&so
->so_rcv
, 1024) == 0) {
np
= mtod(m
, struct nspcb
*);
sp
->so_pcb
= (caddr_t
)np
;
sdn
= (struct sockaddr_dn
*)&so
->so_addr
;
sdn
->sdn_family
== AF_DECNET
;
sdn
->sdn_addr
= WHAT ELSE NEEDS TO BE FILLED IN HERE
?
if (so
->so_options
& SO_ACCEPTCONN
) {
/*** BEGIN NOT MODIFIED FOR NSP ***/
* Initiate (or continue) disconnect.
* If embryonic state, just send reset (once).
* If not in ``let data drain'' option, just drop.
* Otherwise (hard), mark socket disconnecting and drop
* current input data; switch states based on user close, and
* send segment to peer (with FIN).
struct socket
*so
= np
->n_socket
;
if (np
->n_state
< NSPS_ESTABLISHED
)
else if (so
->so_linger
== 0)
* User issued close, and wish to trail through shutdown states:
* if never received SYN, just forget it. If got a SYN from peer,
* but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
* If already got a FIN from peer, then almost done; go to LAST_ACK
* state. In all other cases, have already sent FIN to peer (e.g.
* after PRU_SHUTDOWN), and just have to play tedious game waiting
* for peer to send FIN or not respond to keep-alives, etc.
np
->n_state
= NSPS_CLOSED
;
np
->n_state
= NSPS_FIN_WAIT_1
;
np
->n_state
= NSPS_LAST_ACK
;