From 117d437c2142ecf94953220f15e550d22d0a4e3b Mon Sep 17 00:00:00 2001 From: Jan Lentfer Date: Sun, 12 Sep 2010 00:34:08 +0200 Subject: [PATCH] pf: Make pf work w/ the MPSAFE network stack --- sys/net/pf/if_pflog.c | 13 +++++-- sys/net/pf/pf.c | 55 +++++++++++++++++++++++++++--- sys/net/pf/pf_ioctl.c | 79 +++++++++++++++++++++++++++++++++++++------ sys/net/pf/pfvar.h | 2 ++ 4 files changed, 131 insertions(+), 18 deletions(-) diff --git a/sys/net/pf/if_pflog.c b/sys/net/pf/if_pflog.c index 98344f39f1..3c2a471f58 100644 --- a/sys/net/pf/if_pflog.c +++ b/sys/net/pf/if_pflog.c @@ -114,14 +114,21 @@ pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param __unused) struct ifnet *ifp; struct pflog_softc *pflogif; - if (unit >= PFLOGIFS_MAX) + lwkt_gettoken(&pf_token); + + if (unit >= PFLOGIFS_MAX) { + lwkt_reltoken(&pf_token); return (EINVAL); + } - if ((pflogif = kmalloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK)) == NULL) + if ((pflogif = kmalloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK)) == NULL) { + lwkt_reltoken(&pf_token); return (ENOMEM); + } bzero(pflogif, sizeof(*pflogif)); pflogif->sc_unit = unit; + lwkt_reltoken(&pf_token); ifp = &pflogif->sc_if; ksnprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); ifp->if_softc = pflogif; @@ -135,12 +142,14 @@ pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param __unused) if_attach(ifp, NULL); bpfattach(&pflogif->sc_if, DLT_PFLOG, PFLOG_HDRLEN); + lwkt_gettoken(&pf_token); crit_enter(); LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); pflogifs[unit] = ifp; crit_exit(); + lwkt_reltoken(&pf_token); return (0); } diff --git a/sys/net/pf/pf.c b/sys/net/pf/pf.c index 10675f40bd..2c6901f209 100644 --- a/sys/net/pf/pf.c +++ b/sys/net/pf/pf.c @@ -110,6 +110,8 @@ extern int ip_optcopy(struct ip *, struct ip *); extern int debug_pfugidhack; +struct lwkt_token pf_token = LWKT_TOKEN_MP_INITIALIZER(pf_token); + #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) kprintf x /* @@ -1045,11 +1047,13 @@ void pf_unlink_state(struct pf_state *cur) { if (cur->src.state == PF_TCPS_PROXY_DST) { + lwkt_reltoken(&pf_token); pf_send_tcp(cur->rule.ptr, cur->state_key->af, &cur->state_key->ext.addr, &cur->state_key->lan.addr, cur->state_key->ext.port, cur->state_key->lan.port, cur->src.seqhi, cur->src.seqlo + 1, TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); + lwkt_gettoken(&pf_token); } RB_REMOVE(pf_state_tree_id, &tree_id, cur); #if NPFSYNC @@ -1628,6 +1632,8 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, struct tcphdr *th = NULL; char *opt; + lwkt_gettoken(&pf_token); + /* maximum segment size tcp option */ tlen = sizeof(struct tcphdr); if (mss) @@ -1648,8 +1654,10 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, /* create outgoing mbuf */ m = m_gethdr(MB_DONTWAIT, MT_HEADER); - if (m == NULL) + if (m == NULL) { + lwkt_reltoken(&pf_token); return; + } if (tag) m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; m->m_pkthdr.pf.tag = rtag; @@ -1730,7 +1738,9 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h->ip_ttl = ttl ? ttl : ip_defttl; h->ip_sum = 0; if (eh == NULL) { + lwkt_reltoken(&pf_token); ip_output(m, NULL, NULL, 0, NULL, NULL); + lwkt_gettoken(&pf_token); } else { struct route ro; struct rtentry rt; @@ -1738,6 +1748,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, if (ifp == NULL) { m_freem(m); + lwkt_reltoken(&pf_token); return; } rt.rt_ifp = ifp; @@ -1748,8 +1759,10 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN); e->ether_type = eh->ether_type; /* XXX_IMPORT: later */ + lwkt_reltoken(&pf_token); ip_output(m, (void *)NULL, &ro, 0, (void *)NULL, (void *)NULL); + lwkt_gettoken(&pf_token); } break; #endif /* INET */ @@ -1762,10 +1775,13 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h6->ip6_vfc |= IPV6_VERSION; h6->ip6_hlim = IPV6_DEFHLIM; + lwkt_reltoken(&pf_token); ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + lwkt_gettoken(&pf_token); break; #endif /* INET6 */ } + lwkt_reltoken(&pf_token); } void @@ -3359,10 +3375,12 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, ack++; if (th->th_flags & TH_FIN) ack++; + lwkt_reltoken(&pf_token); pf_send_tcp(r, af, pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + lwkt_gettoken(&pf_token); } } else if ((af == AF_INET) && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, @@ -3627,9 +3645,11 @@ cleanup: mss = pf_calc_mss(saddr, af, mss); mss = pf_calc_mss(daddr, af, mss); s->src.mss = mss; + lwkt_reltoken(&pf_token); pf_send_tcp(r, af, daddr, saddr, th->th_dport, th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); + lwkt_gettoken(&pf_token); REASON_SET(&reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } @@ -3776,11 +3796,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } + lwkt_reltoken(&pf_token); pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, (*state)->src.seqhi, ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 0, NULL, NULL); + lwkt_gettoken(&pf_token); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || @@ -3815,10 +3837,12 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.max_win = MAX(ntohs(th->th_win), 1); if ((*state)->dst.seqhi == 1) (*state)->dst.seqhi = htonl(karc4random()); + lwkt_reltoken(&pf_token); pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, &dst->addr, src->port, dst->port, (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); + lwkt_gettoken(&pf_token); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != @@ -3829,6 +3853,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } else { (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); (*state)->dst.seqlo = ntohl(th->th_seq); + lwkt_reltoken(&pf_token); pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ntohl(th->th_seq) + 1, @@ -3839,6 +3864,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0, NULL, NULL); + lwkt_gettoken(&pf_token); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - @@ -4157,12 +4183,14 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.state == TCPS_SYN_SENT) { /* Send RST for state mismatches during handshake */ if (!(th->th_flags & TH_RST)) + lwkt_reltoken(&pf_token); pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), 0, TH_RST, 0, 0, (*state)->rule.ptr->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + lwkt_gettoken(&pf_token); src->seqlo = 0; src->seqhi = 1; src->max_win = 1; @@ -4205,7 +4233,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, * the protocol stack on the wrong cpu for the * post-translated address. */ - m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH; + /* m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH; */ + m->m_flags &= ~M_HASH; pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, &th->th_sum, &(*state)->state_key->lan.addr, (*state)->state_key->lan.port, 0, pd->af); @@ -4276,7 +4305,8 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, * the protocol stack on the wrong cpu for the * post-translated address. */ - m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH; + /* m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH; */ + m->m_flags &= ~M_HASH; pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, &uh->uh_sum, &(*state)->state_key->lan.addr, (*state)->state_key->lan.port, 1, pd->af); @@ -5097,6 +5127,8 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) #endif int ret = 0; + lwkt_gettoken(&pf_token); + bzero(&ro, sizeof(ro)); switch (af) { case AF_INET: @@ -5114,6 +5146,7 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) break; #endif /* INET6 */ default: + lwkt_reltoken(&pf_token); return (0); } @@ -5123,6 +5156,7 @@ rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING)); RTFREE(ro.ro_rt); } + lwkt_reltoken(&pf_token); return (ret); } @@ -5145,6 +5179,8 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct m_tag *mtag; #endif /* IPSEC */ + lwkt_gettoken(&pf_token); + if (m == NULL || *m == NULL || r == NULL || (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); @@ -5161,11 +5197,15 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, } if (r->rt == PF_DUPTO) { - if ((m0 = m_dup(*m, MB_DONTWAIT)) == NULL) + if ((m0 = m_dup(*m, MB_DONTWAIT)) == NULL) { + lwkt_reltoken(&pf_token); return; + } } else { - if ((r->rt == PF_REPLYTO) == (r->direction == dir)) + if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { + lwkt_reltoken(&pf_token); return; + } m0 = *m; } @@ -5261,9 +5301,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); } } + lwkt_reltoken(&pf_token); crit_exit(); error = ifp->if_output(ifp, m0, sintosa(dst), ro->ro_rt); crit_enter(); + lwkt_gettoken(&pf_token); goto done; } @@ -5293,10 +5335,12 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, m1 = m0->m_nextpkt; m0->m_nextpkt = 0; if (error == 0) { + lwkt_reltoken(&pf_token); crit_exit(); error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); crit_enter(); + lwkt_gettoken(&pf_token); } else m_freem(m0); } @@ -5309,6 +5353,7 @@ done: *m = NULL; if (ro == &iproute && ro->ro_rt) RTFREE(ro->ro_rt); + lwkt_reltoken(&pf_token); return; bad: diff --git a/sys/net/pf/pf_ioctl.c b/sys/net/pf/pf_ioctl.c index c69546e2f1..b234bc7197 100644 --- a/sys/net/pf/pf_ioctl.c +++ b/sys/net/pf/pf_ioctl.c @@ -330,18 +330,26 @@ pfattach(void) int pfopen(struct dev_open_args *ap) { + lwkt_gettoken(&pf_token); cdev_t dev = ap->a_head.a_dev; - if (minor(dev) >= 1) + if (minor(dev) >= 1) { + lwkt_reltoken(&pf_token); return (ENXIO); + } + lwkt_reltoken(&pf_token); return (0); } int pfclose(struct dev_close_args *ap) { + lwkt_gettoken(&pf_token); cdev_t dev = ap->a_head.a_dev; - if (minor(dev) >= 1) + if (minor(dev) >= 1) { + lwkt_reltoken(&pf_token); return (ENXIO); + } + lwkt_reltoken(&pf_token); return (0); } @@ -1068,6 +1076,8 @@ pfioctl(struct dev_ioctl_args *ap) struct pf_pool *pool = NULL; int error = 0; + lwkt_gettoken(&pf_token); + /* XXX keep in sync with switch() below */ if (securelevel > 1) switch (cmd) { @@ -1116,8 +1126,10 @@ pfioctl(struct dev_ioctl_args *ap) if (((struct pfioc_table *)addr)->pfrio_flags & PFR_FLAG_DUMMY) break; /* dummy operation ok */ + lwkt_reltoken(&pf_token); return (EPERM); default: + lwkt_reltoken(&pf_token); return (EPERM); } @@ -1159,12 +1171,16 @@ pfioctl(struct dev_ioctl_args *ap) if (((struct pfioc_table *)addr)->pfrio_flags & PFR_FLAG_DUMMY) break; /* dummy operation ok */ + lwkt_reltoken(&pf_token); return (EACCES); case DIOCGETRULE: - if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR) + if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR) { + lwkt_reltoken(&pf_token); return (EACCES); + } break; default: + lwkt_reltoken(&pf_token); return (EACCES); } @@ -3056,6 +3072,7 @@ pfioctl(struct dev_ioctl_args *ap) break; } fail: + lwkt_reltoken(&pf_token); return (error); } @@ -3193,11 +3210,14 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) */ int chk; + lwkt_gettoken(&pf_token); + chk = pf_test(PF_IN, ifp, m, NULL, NULL); if (chk && *m) { m_freem(*m); *m = NULL; } + lwkt_reltoken(&pf_token); return chk; } @@ -3211,6 +3231,8 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) */ int chk; + lwkt_gettoken(&pf_token); + /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(*m); @@ -3221,6 +3243,7 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) m_freem(*m); *m = NULL; } + lwkt_reltoken(&pf_token); return chk; } @@ -3233,11 +3256,14 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) */ int chk; + lwkt_gettoken(&pf_token); + chk = pf_test6(PF_IN, ifp, m, NULL, NULL); if (chk && *m) { m_freem(*m); *m = NULL; } + lwkt_reltoken(&pf_token); return chk; } @@ -3249,6 +3275,8 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) */ int chk; + lwkt_gettoken(&pf_token); + /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(*m); @@ -3259,6 +3287,7 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) m_freem(*m); *m = NULL; } + lwkt_reltoken(&pf_token); return chk; } #endif /* INET6 */ @@ -3270,13 +3299,19 @@ hook_pf(void) #ifdef INET6 struct pfil_head *pfh_inet6; #endif - - if (pf_pfil_hooked) - return (0); + + lwkt_gettoken(&pf_token); + + if (pf_pfil_hooked) { + lwkt_reltoken(&pf_token); + return (0); + } pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); - if (pfh_inet == NULL) + if (pfh_inet == NULL) { + lwkt_reltoken(&pf_token); return (ENODEV); + } pfil_add_hook(pf_check_in, NULL, PFIL_IN, pfh_inet); pfil_add_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet); #ifdef INET6 @@ -3284,6 +3319,7 @@ hook_pf(void) if (pfh_inet6 == NULL) { pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet); pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet); + lwkt_reltoken(&pf_token); return (ENODEV); } pfil_add_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6); @@ -3291,6 +3327,7 @@ hook_pf(void) #endif pf_pfil_hooked = 1; + lwkt_reltoken(&pf_token); return (0); } @@ -3302,23 +3339,32 @@ dehook_pf(void) struct pfil_head *pfh_inet6; #endif - if (pf_pfil_hooked == 0) + lwkt_gettoken(&pf_token); + + if (pf_pfil_hooked == 0) { + lwkt_reltoken(&pf_token); return (0); + } pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); - if (pfh_inet == NULL) + if (pfh_inet == NULL) { + lwkt_reltoken(&pf_token); return (ENODEV); + } pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet); pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet); #ifdef INET6 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); - if (pfh_inet6 == NULL) + if (pfh_inet6 == NULL) { + lwkt_reltoken(&pf_token); return (ENODEV); + } pfil_remove_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6); pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT, pfh_inet6); #endif pf_pfil_hooked = 0; + lwkt_reltoken(&pf_token); return (0); } @@ -3327,6 +3373,8 @@ pf_load(void) { int error; + lwkt_gettoken(&pf_token); + init_zone_var(); lockinit(&pf_mod_lck, "pf task lck", 0, LK_CANRECURSE); pf_dev = make_dev(&pf_ops, 0, 0, 0, 0600, PF_NAME); @@ -3334,9 +3382,11 @@ pf_load(void) if (error) { dev_ops_remove_all(&pf_ops); lockuninit(&pf_mod_lck); + lwkt_reltoken(&pf_token); return (error); } lockinit(&pf_consistency_lock, "pfconslck", 0, LK_CANRECURSE); + lwkt_reltoken(&pf_token); return (0); } @@ -3344,8 +3394,10 @@ static int pf_unload(void) { int error; - pf_status.running = 0; + + lwkt_gettoken(&pf_token); + error = dehook_pf(); if (error) { /* @@ -3354,6 +3406,7 @@ pf_unload(void) * a message like 'No such process'. */ kprintf("pfil unregistration fail\n"); + lwkt_reltoken(&pf_token); return error; } shutdown_pf(); @@ -3370,6 +3423,7 @@ pf_unload(void) dev_ops_remove_all(&pf_ops); lockuninit(&pf_consistency_lock); lockuninit(&pf_mod_lck); + lwkt_reltoken(&pf_token); return 0; } @@ -3378,6 +3432,8 @@ pf_modevent(module_t mod, int type, void *data) { int error = 0; + lwkt_gettoken(&pf_token); + switch(type) { case MOD_LOAD: error = pf_load(); @@ -3390,6 +3446,7 @@ pf_modevent(module_t mod, int type, void *data) error = EINVAL; break; } + lwkt_reltoken(&pf_token); return error; } diff --git a/sys/net/pf/pfvar.h b/sys/net/pf/pfvar.h index 4010eb0d44..1a0de0784b 100644 --- a/sys/net/pf/pfvar.h +++ b/sys/net/pf/pfvar.h @@ -68,6 +68,8 @@ union sockaddr_union { struct ip; struct ip6_hdr; +extern struct lwkt_token pf_token; + #define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0) #define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1) -- 2.41.0