inpcb: Add in_pcb{link,unlink}_flags() to bypass INP_WILDCARD check
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 22 Sep 2014 11:27:07 +0000 (19:27 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 28 Sep 2014 12:49:11 +0000 (20:49 +0800)
It is safe to change the inpcb's pcblist while the it is still referenced
by the wildcard hash.

sys/netinet/in_pcb.c
sys/netinet/in_pcb.h

index c79ef8b..99aef0d 100644 (file)
@@ -315,30 +315,42 @@ in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo)
  * inp_pcbinfo, NULL it out so we assert if it does.
  */
 void
-in_pcbunlink(struct inpcb *inp, struct inpcbinfo *pcbinfo)
+in_pcbunlink_flags(struct inpcb *inp, struct inpcbinfo *pcbinfo, int flags)
 {
        KASSERT(inp->inp_pcbinfo == pcbinfo, ("pcbinfo mismatch"));
-       KASSERT((inp->inp_flags & (INP_WILDCARD | INP_CONNECTED)) == 0,
+       KASSERT((inp->inp_flags & (flags | INP_CONNECTED)) == 0,
            ("already linked"));
 
        in_pcbofflist(inp);
        inp->inp_pcbinfo = NULL;
 }
 
+void
+in_pcbunlink(struct inpcb *inp, struct inpcbinfo *pcbinfo)
+{
+       in_pcbunlink_flags(inp, pcbinfo, INP_WILDCARD);
+}
+
 /*
  * Relink a pcb into a new pcbinfo.
  */
 void
-in_pcblink(struct inpcb *inp, struct inpcbinfo *pcbinfo)
+in_pcblink_flags(struct inpcb *inp, struct inpcbinfo *pcbinfo, int flags)
 {
        KASSERT(inp->inp_pcbinfo == NULL, ("has pcbinfo"));
-       KASSERT((inp->inp_flags & (INP_WILDCARD | INP_CONNECTED)) == 0,
+       KASSERT((inp->inp_flags & (flags | INP_CONNECTED)) == 0,
            ("already linked"));
 
        inp->inp_pcbinfo = pcbinfo;
        in_pcbonlist(inp);
 }
 
+void
+in_pcblink(struct inpcb *inp, struct inpcbinfo *pcbinfo)
+{
+       return in_pcblink_flags(inp, pcbinfo, INP_WILDCARD);
+}
+
 static int
 in_pcbsetlport(struct inpcb *inp, int wild, struct ucred *cred)
 {
index 11c70ae..7b4eadb 100644 (file)
@@ -482,7 +482,9 @@ void        in_pcbinfo_init (struct inpcbinfo *, int, boolean_t);
 void   in_pcbportinfo_init (struct inpcbportinfo *, int, boolean_t, u_short);
 int    in_pcballoc (struct socket *, struct inpcbinfo *);
 void   in_pcbunlink (struct inpcb *, struct inpcbinfo *);
+void   in_pcbunlink_flags (struct inpcb *, struct inpcbinfo *, int);
 void   in_pcblink (struct inpcb *, struct inpcbinfo *);
+void   in_pcblink_flags (struct inpcb *, struct inpcbinfo *, int);
 void   in_pcbonlist (struct inpcb *);
 void   in_pcbofflist (struct inpcb *);
 int    in_pcbbind (struct inpcb *, struct sockaddr *, struct thread *);