-/* in_pcb.c 4.30 82/07/24 */
+/* in_pcb.c 4.31 82/09/26 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../net/in_pcb.h"
#include "../h/protosw.h"
-/*
- * Routines to manage internet protocol control blocks.
- *
- * At PRU_ATTACH time a protocol control block is allocated in
- * in_pcballoc() and inserted on a doubly-linked list of such blocks
- * for the protocol. A port address is either requested (and verified
- * to not be in use) or assigned at this time. We also allocate
- * space in the socket sockbuf structures here, although this is
- * not a clearly correct place to put this function.
- *
- * A connectionless protocol will have its protocol control block
- * removed at PRU_DETACH time, when the socket will be freed (freeing
- * the space reserved) and the block will be removed from the list of
- * blocks for its protocol.
- *
- * A connection-based protocol may be connected to a remote peer at
- * PRU_CONNECT time through the routine in_pcbconnect(). In the normal
- * case a PRU_DISCONNECT occurs causing a in_pcbdisconnect().
- * It is also possible that higher-level routines will opt out of the
- * relationship with the connection before the connection shut down
- * is complete. This often occurs in protocols like TCP where we must
- * hold on to the protocol control block for a unreasonably long time
- * after the connection is used up to avoid races in later connection
- * establishment. To handle this we allow higher-level routines to
- * disassociate themselves from the socket, marking it SS_NOFDREF while
- * the disconnect is in progress. We notice that this has happened
- * when the disconnect is complete, and perform the PRU_DETACH operation,
- * freeing the socket.
- *
- * TODO:
- * use hashing
- */
struct in_addr zeroin_addr;
in_pcbreserve(so, sndcc, rcvcc)
return (0);
}
-in_pcbbind(inp, sin)
+in_pcbbind(inp, nam)
register struct inpcb *inp;
- struct sockaddr_in *sin;
+ struct mbuf *nam;
{
register struct socket *so = inp->inp_socket;
register struct inpcb *head = inp->inp_head;
+ register struct sockaddr_in *sin;
u_short lport = 0;
if (ifnet == 0)
return (EADDRNOTAVAIL);
- if (sin) {
- if (sin->sin_family != AF_INET)
- return (EAFNOSUPPORT);
- if (sin->sin_addr.s_addr) {
- int tport = sin->sin_port;
+ if (inp->inp_lport || inp->inp_laddr.s_addr)
+ return (EINVAL);
+ if (nam == 0)
+ goto noname;
+ sin = mtod(nam, struct sockaddr_in *);
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ if (sin->sin_addr.s_addr) {
+ int tport = sin->sin_port;
- sin->sin_port = 0; /* yech... */
- if (if_ifwithaddr((struct sockaddr *)sin) == 0)
- return (EADDRNOTAVAIL);
- sin->sin_port = tport;
- }
- lport = sin->sin_port;
- if (lport) {
- u_short aport = lport;
- int wild = 0;
-#if vax
- aport = htons(aport);
-#endif
- /* GROSS */
- if (aport < IPPORT_RESERVED && u.u_uid != 0)
- return (EACCES);
- if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
- (so->so_options & SO_ACCEPTCONN) == 0)
- wild = INPLOOKUP_WILDCARD;
- if (in_pcblookup(head,
- zeroin_addr, 0, sin->sin_addr, lport, wild))
- return (EADDRINUSE);
- }
+ sin->sin_port = 0; /* yech... */
+ if (if_ifwithaddr((struct sockaddr *)sin) == 0)
+ return (EADDRNOTAVAIL);
+ sin->sin_port = tport;
}
- if (sin)
- inp->inp_laddr = sin->sin_addr;
- if (lport == 0)
- do {
- if (head->inp_lport++ < IPPORT_RESERVED)
- head->inp_lport = IPPORT_RESERVED;
- lport = htons(head->inp_lport);
- } while (in_pcblookup(head,
- zeroin_addr, 0, inp->inp_laddr, lport, 0));
- inp->inp_lport = lport;
- return (0);
-}
-
-/* BEGIN DEPRECATED */
-/*
- * Allocate a protocol control block, space
- * for send and receive data, and local host information.
- * Return error. If no error make socket point at pcb.
- */
-in_pcbattach(so, head, sndcc, rcvcc, sin)
- struct socket *so;
- struct inpcb *head;
- int sndcc, rcvcc;
- struct sockaddr_in *sin;
-{
- struct mbuf *m;
- register struct inpcb *inp;
- u_short lport = 0;
-
- if (ifnet == 0)
- return (EADDRNOTAVAIL);
- if (sin) {
- if (sin->sin_family != AF_INET)
- return (EAFNOSUPPORT);
- if (sin->sin_addr.s_addr) {
- int tport = sin->sin_port;
+ lport = sin->sin_port;
+ if (lport) {
+ u_short aport = lport;
+ int wild = 0;
- sin->sin_port = 0; /* yech... */
- if (if_ifwithaddr((struct sockaddr *)sin) == 0)
- return (EADDRNOTAVAIL);
- sin->sin_port = tport;
- }
- lport = sin->sin_port;
- if (lport) {
- u_short aport = lport;
- int wild = 0;
#if vax
- aport = htons(aport);
+ aport = htons(aport);
#endif
- /* GROSS */
- if (aport < IPPORT_RESERVED && u.u_uid != 0)
- return (EACCES);
- if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
- (so->so_options & SO_ACCEPTCONN) == 0)
- wild = INPLOOKUP_WILDCARD;
- if (in_pcblookup(head,
- zeroin_addr, 0, sin->sin_addr, lport, wild))
- return (EADDRINUSE);
- }
+ /* GROSS */
+ if (aport < IPPORT_RESERVED && u.u_uid != 0)
+ return (EACCES);
+ if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0)
+ wild = INPLOOKUP_WILDCARD;
+ if (in_pcblookup(head,
+ zeroin_addr, 0, sin->sin_addr, lport, wild))
+ return (EADDRINUSE);
}
- m = m_getclr(M_DONTWAIT);
- if (m == 0)
- return (ENOBUFS);
- if (sbreserve(&so->so_snd, sndcc) == 0)
- goto bad;
- if (sbreserve(&so->so_rcv, rcvcc) == 0)
- goto bad2;
- inp = mtod(m, struct inpcb *);
- inp->inp_head = head;
- if (sin)
- inp->inp_laddr = sin->sin_addr;
+ inp->inp_laddr = sin->sin_addr;
+noname:
if (lport == 0)
do {
if (head->inp_lport++ < IPPORT_RESERVED)
} while (in_pcblookup(head,
zeroin_addr, 0, inp->inp_laddr, lport, 0));
inp->inp_lport = lport;
- inp->inp_socket = so;
- insque(inp, head);
- so->so_pcb = (caddr_t)inp;
return (0);
-bad2:
- sbrelease(&so->so_snd);
-bad:
- (void) m_free(m);
- return (ENOBUFS);
}
-/* END DEPRECATED */
/*
* Connect from a socket to a specified address.
* If don't have a local address for this socket yet,
* then pick one.
*/
-in_pcbconnect(inp, sin)
+in_pcbconnect(inp, nam)
struct inpcb *inp;
- struct sockaddr_in *sin;
+ struct mbuf *nam;
{
struct ifnet *ifp;
struct sockaddr_in *ifaddr;
+ register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
if (sin->sin_family != AF_INET)
return (EAFNOSUPPORT);
if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
(void) m_free(dtom(inp));
}
-in_setsockaddr(sin, inp)
- register struct sockaddr_in *sin;
+in_setsockaddr(inp, nam)
register struct inpcb *inp;
+ struct mbuf *nam;
{
- if (sin == 0 || inp == 0)
- panic("setsockaddr_in");
+ register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+
+ nam->m_len = sizeof (*sin);
+ sin = mtod(nam, struct sockaddr_in *);
bzero((caddr_t)sin, sizeof (*sin));
sin->sin_family = AF_INET;
sin->sin_port = inp->inp_lport;
splx(s);
}
-/*
- * SHOULD ALLOW MATCH ON MULTI-HOMING ONLY
- */
struct inpcb *
in_pcblookup(head, faddr, fport, laddr, lport, flags)
struct inpcb *head;
-/* tcp_input.c 1.73 82/07/24 */
+/* tcp_input.c 1.74 82/09/26 */
#include "../h/param.h"
#include "../h/systm.h"
int tcpprintfs = 0;
int tcpcksum = 1;
-struct sockaddr_in tcp_in = { AF_INET };
+struct mbuf tcp_mb;
struct tcpiphdr tcp_saveti;
extern tcpnodelack;
#endif
/*
- * Locate pcb for segment. On match, update the local
- * address stored in the block to reflect anchoring.
+ * Locate pcb for segment.
*/
inp = in_pcblookup
(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport,
* Enter SYN_RECEIVED state, and process any other fields of this
* segment in this state.
*/
- case TCPS_LISTEN:
+ case TCPS_LISTEN: {
+ struct mbuf *m = m_get(M_DONTWAIT);
+ register struct sockaddr_in *sin;
+
+ if (m == 0)
+ goto drop;
+ m->m_off = MMINOFF;
+ m->m_len = sizeof (struct sockaddr_in);
if (tiflags & TH_RST)
goto drop;
if (tiflags & TH_ACK)
goto dropwithreset;
if ((tiflags & TH_SYN) == 0)
goto drop;
- tcp_in.sin_addr = ti->ti_src;
- tcp_in.sin_port = ti->ti_sport;
+ sin = mtod(m, struct sockaddr_in *);
+ sin->sin_family = AF_INET;
+ sin->sin_addr = ti->ti_src;
+ sin->sin_port = ti->ti_sport;
laddr = inp->inp_laddr;
if (inp->inp_laddr.s_addr == 0)
inp->inp_laddr = ti->ti_dst;
- if (in_pcbconnect(inp, (struct sockaddr_in *)&tcp_in)) {
+ if (in_pcbconnect(inp, m)) {
inp->inp_laddr = laddr;
+ m_free(m);
goto drop;
}
+ m_free(m);
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
in_pcbdisconnect(inp);
tp->t_state = TCPS_SYN_RECEIVED;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
goto trimthenstep6;
+ }
/*
* If the state is SYN_SENT:
-/* tcp_usrreq.c 1.61 82/07/24 */
+/* tcp_usrreq.c 1.62 82/09/26 */
#include "../h/param.h"
#include "../h/systm.h"
* 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.
*/
-tcp_usrreq(so, req, m, addr)
+tcp_usrreq(so, req, m, nam, opt)
struct socket *so;
int req;
- struct mbuf *m;
- caddr_t addr;
+ struct mbuf *m, *nam;
+ struct socketopt *opt;
{
register struct inpcb *inp = sotoinpcb(so);
register struct tcpcb *tp;
* 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).
- * 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 (inp == 0 && req != PRU_ATTACH) {
splx(s);
}
if (inp) {
tp = intotcpcb(inp);
+ /* WHAT IF TP IS 0? */
#ifdef KPROF
tcp_acounts[tp->t_state][req]++;
#endif
/*
* TCP attaches to socket via PRU_ATTACH, reserving space,
- * and internet and TCP control blocks.
- * If the socket is to receive connections,
- * then the LISTEN state is entered.
+ * and an internet control block.
*/
case PRU_ATTACH:
if (inp) {
error = EISCONN;
break;
}
- error = tcp_attach(so, (struct sockaddr *)addr);
+ error = tcp_attach(so, nam);
if (error)
break;
if ((so->so_options & SO_DONTLINGER) == 0)
}
break;
+ /*
+ * Give the socket an address.
+ */
+ case PRU_BIND:
+ error = in_pcbbind(inp, nam);
+ if (error)
+ break;
+ break;
+
+ /*
+ * Prepare to accept connections.
+ */
+ case PRU_LISTEN:
+ if (inp->inp_lport == 0)
+ error = in_pcbbind(inp, (struct mbuf *)0);
+ if (error == 0)
+ tp->t_state = TCPS_LISTEN;
+ break;
+
/*
* Initiate connection to peer.
* Create a template for use in transmissions on this connection.
* Send initial segment on connection.
*/
case PRU_CONNECT:
- error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
+ if (inp->inp_lport == 0) {
+ error = in_pcbbind(inp, (struct mbuf *)0);
+ if (error)
+ break;
+ }
+ error = in_pcbconnect(inp, nam);
if (error)
break;
tp->t_template = tcp_template(tp);
* of the peer, storing through addr.
*/
case PRU_ACCEPT: {
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
- if (sin) {
- bzero((caddr_t)sin, sizeof (*sin));
- sin->sin_family = AF_INET;
- sin->sin_port = inp->inp_fport;
- sin->sin_addr = inp->inp_faddr;
- }
- }
+ nam->m_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_port = inp->inp_fport;
+ sin->sin_addr = inp->inp_faddr;
break;
+ }
/*
* Mark the connection as being incapable of further output.
break;
case PRU_SOCKADDR:
- in_setsockaddr((struct sockaddr_in *)addr, inp);
+ in_setsockaddr(inp, nam);
break;
/*
* routine for tracing's sake.
*/
case PRU_SLOWTIMO:
- tcp_timers(tp, (int)addr);
- req |= (int)addr << 8; /* for debug's sake */
+ tcp_timers(tp, (int)nam);
+ req |= (int)nam << 8; /* for debug's sake */
break;
default:
* internet protocol control block, tcp control block,
* bufer space, and entering LISTEN state if to accept connections.
*/
-tcp_attach(so, sa)
+tcp_attach(so)
struct socket *so;
- struct sockaddr *sa;
{
register struct tcpcb *tp;
struct inpcb *inp;
goto bad;
error = in_pcballoc(so, &tcb);
if (error)
- goto bad2;
- inp = (struct inpcb *)so->so_pcb;
- if (sa || ((so->so_options & SO_ACCEPTCONN) == 0 && so->so_head == 0)) {
- error = in_pcbbind(inp, sa);
- if (error)
- goto bad2;
- }
+ goto bad;
+ inp = sotoinpcb(so);
tp = tcp_newtcpcb(inp);
if (tp == 0) {
error = ENOBUFS;
goto bad2;
}
- tp->t_state =
- (so->so_options & SO_ACCEPTCONN) ? TCPS_LISTEN : TCPS_CLOSED;
+ tp->t_state = TCPS_CLOSED;
return (0);
bad2:
in_pcbdetach(inp);
-/* udp_usrreq.c 4.31 82/08/15 */
+/* udp_usrreq.c 4.32 82/09/26 */
#include "../h/param.h"
#include "../h/dir.h"
so->so_state & SS_PRIV));
}
-udp_usrreq(so, req, m, addr)
+udp_usrreq(so, req, m, nam, opt)
struct socket *so;
int req;
- struct mbuf *m;
- caddr_t addr;
+ struct mbuf *m, *nam;
+ struct socketopt *opt;
{
struct inpcb *inp = sotoinpcb(so);
int error = 0;
case PRU_ATTACH:
if (inp != 0)
return (EINVAL);
- error = in_pcbattach(so, &udb, 2048, 2048,
- (struct sockaddr_in *)addr);
+ error = in_pcballoc(so, &udb);
+ if (error)
+ break;
+ error = in_pcbreserve(so, 2048, 2048);
+ if (error)
+ break;
break;
case PRU_DETACH:
in_pcbdetach(inp);
break;
+ case PRU_BIND:
+ error = in_pcbbind(inp, nam);
+ break;
+
+ case PRU_LISTEN:
+ error = EOPNOTSUPP;
+ break;
+
case PRU_CONNECT:
if (inp->inp_faddr.s_addr)
return (EISCONN);
- error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
+ error = in_pcbconnect(inp, nam);
if (error == 0)
soisconnected(so);
break;
case PRU_SEND: {
struct in_addr laddr;
- if (addr) {
+ if (nam) {
laddr = inp->inp_laddr;
if (inp->inp_faddr.s_addr)
return (EISCONN);
- error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
+ error = in_pcbconnect(inp, nam);
if (error)
break;
} else {
return (ENOTCONN);
}
error = udp_output(inp, m);
- if (addr) {
+ if (nam) {
in_pcbdisconnect(inp);
inp->inp_laddr = laddr;
}
return (EOPNOTSUPP);
case PRU_SOCKADDR:
- in_setsockaddr((struct sockaddr_in *)addr, inp);
+ in_setsockaddr(inp, nam);
break;
default: