* Copyright (c) 1992 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)tuba_usrreq.c 7.4 (Berkeley) %G%
#include <sys/socketvar.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
#include <netinet/tcp_debug.h>
#include <netiso/argo_debug.h>
#include <netiso/iso_pcb.h>
#include <netiso/iso_var.h>
#include <netiso/tuba_table.h>
* TCP protocol interface to socket abstraction.
extern char *tcpstates
[];
struct isopcb tuba_isopcb
;
* Process a TCP user request for TCP tb. 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.
tuba_usrreq(so
, req
, m
, nam
, control
)
struct mbuf
*m
, *nam
, *control
;
register struct inpcb
*inp
;
register struct isopcb
*isop
;
register struct tcpcb
*tp
;
struct sockaddr_iso
*siso
;
return (iso_control(so
, (int)m
, (caddr_t
)nam
,
(struct ifnet
*)control
));
* When a TCP is attached to a socket, then there will be
* a (struct inpcb) pointed at by the socket, and this
* structure will point at a subsidary (struct tcpcb).
if (inp
== 0 && req
!= PRU_ATTACH
) {
return (EINVAL
); /* XXX */
isop
= (struct isopcb
*)tp
->t_tuba_pcb
;
* TCP attaches to socket via PRU_ATTACH, reserving space,
* and an internet control block. We also need to
* allocate an isopcb and separate the control block from
if (error
= iso_pcballoc(so
, &tuba_isopcb
))
isop
= (struct isopcb
*)so
->so_pcb
;
if (error
= tcp_usrreq(so
, req
, m
, nam
, control
)) {
tp
->t_tuba_pcb
= (caddr_t
) isop
;
* PRU_DETACH detaches the TCP 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 TCB's can just
if (tp
->t_state
> TCPS_LISTEN
)
* Give the socket an address.
siso
= mtod(nam
, struct sockaddr_iso
*);
if (siso
->siso_tlen
&& siso
->siso_tlen
!= 2) {
if ((error
= iso_pcbbind(isop
, nam
)) ||
(siso
= isop
->isop_laddr
) == 0)
bcopy(TSEL(siso
), &inp
->inp_lport
, 2);
!(inp
->inp_laddr
.s_addr
= tuba_lookup(&siso
->siso_addr
, M_WAITOK
)))
* Prepare to accept connections.
if (inp
->inp_lport
== 0 &&
(error
= iso_pcbbind(isop
, (struct mbuf
*)0)))
bcopy(TSEL(isop
->isop_laddr
), &inp
->inp_lport
, 2);
tp
->t_state
= TCPS_LISTEN
;
* Initiate connection to peer.
* Create a template for use in transmissions on this connection.
* Enter SYN_SENT state, and mark socket as connecting.
* Start keep-alive timer, and seed output sequence space.
* Send initial segment on connection.
if (error
= iso_pcbconnect(isop
, nam
))
siso
= mtod(nam
, struct sockaddr_iso
*);
if (!(inp
->inp_faddr
.s_addr
= tuba_lookup(&siso
->siso_addr
, M_WAITOK
))) {
bcopy(TSEL(isop
->isop_faddr
), &inp
->inp_fport
, 2);
if (inp
->inp_laddr
.s_addr
== 0 &&
tuba_lookup(&isop
->isop_laddr
->siso_addr
, M_WAITOK
)) == 0)
if ((tp
->t_template
= tcp_template(tp
)) == 0)
tcpstat
.tcps_connattempt
++;
tp
->t_state
= TCPS_SYN_SENT
;
tp
->t_timer
[TCPT_KEEP
] = TCPTV_KEEP_INIT
;
tp
->iss
= tcp_iss
; tcp_iss
+= TCP_ISSINCR
/2;
* 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 TCP shutdown process: mark socket disconnecting,
* drain unread data, state switch to reflect user close, and
* send segment (e.g. FIN) to peer. Socket will be really disconnected
* when peer sends FIN and acks ours.
* SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
if ((tp
= tcp_disconnect(tp
)) == 0)
* Accept a connection. Essentially all the work is
* done at higher levels; just return the address
* of the peer, storing through addr.
bcopy((caddr_t
)isop
->isop_faddr
, mtod(m
, caddr_t
),
nam
->m_len
= isop
->isop_faddr
->siso_len
);
* Mark the connection as being incapable of further output.
if ((tp
= tcp_drop(tp
, ECONNABORTED
)) == 0)
bcopy((caddr_t
)isop
->isop_laddr
, mtod(m
, caddr_t
),
nam
->m_len
= isop
->isop_laddr
->siso_len
);
bcopy((caddr_t
)isop
->isop_faddr
, mtod(m
, caddr_t
),
nam
->m_len
= isop
->isop_faddr
->siso_len
);
error
= tcp_usrreq(so
, req
, m
, nam
, control
);
if (tp
&& (so
->so_options
& SO_DEBUG
))
tcp_trace(TA_USER
, ostate
, tp
, (struct tcpiphdr
*)0, req
);
tuba_ctloutput(op
, so
, level
, optname
, mp
)
int clnp_ctloutput(), tcp_ctloutput();
return ((level
!= IPPROTO_TCP
? clnp_ctloutput
: tcp_ctloutput
)
(clnp_ctloutput(op
, so
, level
, optname
, mp
)));