Nothing special, just get assign `inp' and `tp' from passed socket. I
want to do this before (*pru_usrreq)() split to avoid huge code
duplication.
We have "tp might get 0 when using socket splicing" commentary. I
checked where we set `inp_ppcb' to NULL and found, tcp_close() is the
only place, and the following in_pcbdetach() sets `so_pcb' to NULL. So
this commentary looks wrong, because we can't have TCP sockets without
TCP pcb attached.
This diff works fine with sys/kern/sosplice test.
ok?
Index: sys/netinet/tcp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.187
diff -u -p -r1.187 tcp_usrreq.c
--- sys/netinet/tcp_usrreq.c 15 Aug 2022 09:11:39 -0000 1.187
+++ sys/netinet/tcp_usrreq.c 15 Aug 2022 10:51:18 -0000
@@ -142,6 +142,33 @@ struct inpcbtable tcbtable;
int tcp_fill_info(struct tcpcb *, struct socket *, struct mbuf *);
int tcp_ident(void *, size_t *, void *, size_t, int);
+static inline int tcp_sogetpcb(struct socket *, struct inpcb **,
+ struct tcpcb **);
+
+static inline int
+tcp_sogetpcb(struct socket *so, struct inpcb **rinp, struct tcpcb **rtp)
+{
+ struct inpcb *inp;
+
+ /*
+ * 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 subsidiary (struct tcpcb).
+ */
+ if ((inp = sotoinpcb(so)) == NULL) {
+ if (so->so_error)
+ return so->so_error;
+ return EINVAL;
+ }
+
+ *rinp = inp;
+ *rtp = intotcpcb(inp);
+
+ KASSERT(*rtp != NULL);
+
+ return 0;
+}
+
/*
* 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
@@ -153,7 +180,7 @@ tcp_usrreq(struct socket *so, int req, s
struct mbuf *control, struct proc *p)
{
struct inpcb *inp;
- struct tcpcb *otp = NULL, *tp = NULL;
+ struct tcpcb *otp = NULL, *tp;
int error = 0;
short ostate;
@@ -175,22 +202,9 @@ tcp_usrreq(struct socket *so, int req, s
goto release;
}
- inp = sotoinpcb(so);
- /*
- * 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 subsidiary (struct tcpcb).
- */
- if (inp == NULL) {
- error = so->so_error;
- if (error == 0)
- error = EINVAL;
- goto release;
- }
- tp = intotcpcb(inp);
- /* tp might get 0 when using socket splicing */
- if (tp == NULL)
+ if ((error = tcp_sogetpcb(so, &inp, &tp)))
goto release;
+
if (so->so_options & SO_DEBUG) {
otp = tp;
ostate = tp->t_state;
@@ -739,28 +753,15 @@ int
tcp_detach(struct socket *so)
{
struct inpcb *inp;
- struct tcpcb *otp = NULL, *tp = NULL;
+ struct tcpcb *otp = NULL, *tp;
int error = 0;
short ostate;
soassertlocked(so);
- inp = sotoinpcb(so);
- /*
- * 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 subsidiary (struct tcpcb).
- */
- if (inp == NULL) {
- error = so->so_error;
- if (error == 0)
- error = EINVAL;
+ if ((error = tcp_sogetpcb(so, &inp, &tp)))
return (error);
- }
- tp = intotcpcb(inp);
- /* tp might get 0 when using socket splicing */
- if (tp == NULL)
- return (0);
+
if (so->so_options & SO_DEBUG) {
otp = tp;
ostate = tp->t_state;