Hello,

thank you for taking a look at my diff.

</snip>

> >     }
> >  
> > -   if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
> > +   if (kif->pfik_ifp != NULL || kif->pfik_group != NULL ||kif == pfi_all)
> 
> Missing space over                                            ^^^ here

    fixed, looks like unintended change
> > +   if (found == 0) {
> > +           if (name == NULL)
> > +                   return (0);
> > +
> > +           n = strlen(name);
> > +           if ((n < 1) || (n >= IFNAMSIZ))
> I would just use:
>               if (n < 1 || n >= IFNAMSIZ)
> like in other places.

    sure.

> 
> > +                   return (0);
> > +
> > +           if (((name[0] < 'a') || (name[0] > 'z')) ||
> > +               ((name[0] < 'A') && (name[0] > 'Z')))
> > +                   return (0);
> 
> Not sure what you're after here. The logic of this construct is incorrect.
> I would steal the defines from libsa/stand.h and then us !isalpha:
> 
> #define isupper(c)      ((c) >= 'A' && (c) <= 'Z')
> #define islower(c)      ((c) >= 'a' && (c) <= 'z')
> #define isalpha(c)      (isupper(c)||islower(c))
> 
>               if (!isalpha(name[0]))
>                       return (0);
> 
> You can also expand the defines if you want.
> I feel the intention here is to check if this is a interface group. So
> maybe using the check in pfi_skip_if() would be better:
> 
>               if (name[n-1] >= '0' && name[n-1] <= '9')
>                       return (0);     /* group names may not end in a digit */
> 

    it is just sanity check we deal with either interface or group,
    so isalpha(name[0]) is exactly what I want. And thanks for tip
    to steal it from libsa/stand.h. Perhaps one day some day there
    will be ctype.h for for kernel as well.

    the reason to add this extra check is that I want to be sure we eventually
    don't create interface, which starts with space (white char).

    Remember former code did not create interface (kif object), it just walked
    through list of existing interfaces in table. Now the DIOCSETIFFLAG ioctl
    needs to be more cautious.


updated diff is below.

thanks and
regards
sashan


--------8<---------------8<---------------8<------------------8<--------
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index bff448aa8dc..4afe841651f 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1383,9 +1383,6 @@ Packets passing in or out on such interfaces are passed 
as if pf was
 disabled, i.e. pf does not process them in any way.
 This can be useful on loopback and other virtual interfaces, when
 packet filtering is not desired and can have unexpected effects.
-.Ar ifspec
-is only evaluated when the ruleset is loaded; interfaces created
-later will not be skipped.
 PF filters traffic on all interfaces by default.
 .It Ic set Cm state-defaults Ar state-option , ...
 The
diff --git a/sys/net/if.c b/sys/net/if.c
index 2e9a968d7cc..a6d3cb4f4ac 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -2725,6 +2725,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
 
 #if NPF > 0
        pfi_group_addmember(groupname, ifp);
+       pfi_xcommit();
 #endif
 
        return (0);
@@ -2757,7 +2758,7 @@ if_delgroup(struct ifnet *ifp, const char *groupname)
        }
 
 #if NPF > 0
-       pfi_group_change(groupname);
+       pfi_group_delmember(groupname, ifp);
 #endif
 
        KASSERT(ifgl->ifgl_group->ifg_refcnt != 0);
@@ -2769,6 +2770,10 @@ if_delgroup(struct ifnet *ifp, const char *groupname)
                free(ifgl->ifgl_group, M_TEMP, sizeof(*ifgl->ifgl_group));
        }
 
+#if NPF > 0
+       pfi_xcommit();
+#endif
+
        free(ifgl, M_TEMP, sizeof(*ifgl));
 
        return (0);
diff --git a/sys/net/pf_if.c b/sys/net/pf_if.c
index 8de37375ab4..383b8c38f6a 100644
--- a/sys/net/pf_if.c
+++ b/sys/net/pf_if.c
@@ -57,6 +57,10 @@
 #include <netinet/ip6.h>
 #endif /* INET6 */
 
+#define isupper(c)     ((c) >= 'A' && (c) <= 'Z')
+#define islower(c)     ((c) >= 'a' && (c) <= 'z')
+#define isalpha(c)     (isupper(c)||islower(c))
+
 struct pfi_kif          *pfi_all = NULL;
 struct pool              pfi_addr_pl;
 struct pfi_ifhead        pfi_ifs;
@@ -75,6 +79,7 @@ void           pfi_address_add(struct sockaddr *, 
sa_family_t, u_int8_t);
 int             pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
 int             pfi_skip_if(const char *, struct pfi_kif *);
 int             pfi_unmask(void *);
+void            pfi_group_change(const char *);
 
 RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
 RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
@@ -187,6 +192,9 @@ pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
        case PFI_KIF_REF_SRCNODE:
                kif->pfik_srcnodes++;
                break;
+       case PFI_KIF_REF_FLAG:
+               kif->pfik_flagrefs++;
+               break;
        default:
                panic("pfi_kif_ref with unknown type");
        }
@@ -204,7 +212,8 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
        case PFI_KIF_REF_RULE:
                if (kif->pfik_rules <= 0) {
                        DPFPRINTF(LOG_ERR,
-                           "pfi_kif_unref: rules refcount <= 0");
+                           "pfi_kif_unref (%s): rules refcount <= 0",
+                           kif->pfik_name);
                        return;
                }
                kif->pfik_rules--;
@@ -212,7 +221,8 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
        case PFI_KIF_REF_STATE:
                if (kif->pfik_states <= 0) {
                        DPFPRINTF(LOG_ERR,
-                           "pfi_kif_unref: state refcount <= 0");
+                           "pfi_kif_unref (%s): state refcount <= 0",
+                           kif->pfik_name);
                        return;
                }
                kif->pfik_states--;
@@ -220,7 +230,8 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
        case PFI_KIF_REF_ROUTE:
                if (kif->pfik_routes <= 0) {
                        DPFPRINTF(LOG_ERR,
-                           "pfi_kif_unref: route refcount <= 0");
+                           "pfi_kif_unref (%s): route refcount <= 0",
+                           kif->pfik_name);
                        return;
                }
                kif->pfik_routes--;
@@ -228,20 +239,30 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
        case PFI_KIF_REF_SRCNODE:
                if (kif->pfik_srcnodes <= 0) {
                        DPFPRINTF(LOG_ERR,
-                           "pfi_kif_unref: src-node refcount <= 0");
+                           "pfi_kif_unref (%s): src-node refcount <= 0",
+                           kif->pfik_name);
                        return;
                }
                kif->pfik_srcnodes--;
                break;
+       case PFI_KIF_REF_FLAG:
+               if (kif->pfik_flagrefs <= 0) {
+                       DPFPRINTF(LOG_ERR,
+                           "pfi_kif_unref (%s): flags refcount <= 0",
+                           kif->pfik_name);
+                       return;
+               }
+               kif->pfik_flagrefs--;
+               break;
        default:
-               panic("pfi_kif_unref with unknown type");
+               panic("pfi_kif_unref (%s) with unknown type", kif->pfik_name);
        }
 
        if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
                return;
 
        if (kif->pfik_rules || kif->pfik_states || kif->pfik_routes ||
-           kif->pfik_srcnodes)
+           kif->pfik_srcnodes || kif->pfik_flagrefs)
                return;
 
        RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
@@ -353,6 +374,19 @@ pfi_group_change(const char *group)
        pfi_kif_update(kif);
 }
 
+void
+pfi_group_delmember(const char *group, struct ifnet *ifp)
+{
+       struct pfi_kif          *gkif, *ikif;
+
+       if ((gkif = pfi_kif_get(group, NULL)) == NULL ||
+           (ikif = pfi_kif_get(ifp->if_xname, NULL)) == NULL)
+               panic("%s: pfi_kif_get failed", __func__);
+       ikif->pfik_flags_new = ikif->pfik_flags & ~gkif->pfik_flags;
+
+       pfi_group_change(group);
+}
+
 void
 pfi_group_addmember(const char *group, struct ifnet *ifp)
 {
@@ -361,7 +395,7 @@ pfi_group_addmember(const char *group, struct ifnet *ifp)
        if ((gkif = pfi_kif_get(group, NULL)) == NULL ||
            (ikif = pfi_kif_get(ifp->if_xname, NULL)) == NULL)
                panic("%s: pfi_kif_get failed", __func__);
-       ikif->pfik_flags |= gkif->pfik_flags;
+       ikif->pfik_flags_new = ikif->pfik_flags | gkif->pfik_flags;
 
        pfi_group_change(group);        
 }
@@ -786,25 +820,64 @@ int
 pfi_set_flags(const char *name, int flags)
 {
        struct pfi_kif  *p;
+       int found = 0;
+       size_t n;
 
        RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
                if (pfi_skip_if(name, p))
                        continue;
                p->pfik_flags_new = p->pfik_flags | flags;
+               found = 1;
        }
+
+       if (found == 0) {
+               if (name == NULL)
+                       return (0);
+
+               n = strlen(name);
+               if (n < 1 || n >= IFNAMSIZ)
+                       return (0);
+
+               if (!isalpha(name[0]))
+                       return (0);
+
+               p = pfi_kif_get(name, NULL);
+               if (p != NULL) {
+                       p->pfik_flags_new = p->pfik_flags | flags;
+
+                       /*
+                        * We use pfik_flagrefs counter as an indication
+                        * whether the kif has been created on behalf of
+                        * 'pfi_set_flags()' or not.
+                        */
+                       KASSERT((p->pfik_flagrefs == 0) ||
+                           (p->pfik_flagrefs == 1));
+
+                       if ((p->pfik_flags_new != p->pfik_flags) &&
+                           (p->pfik_flagrefs == 0))
+                               pfi_kif_ref(p, PFI_KIF_REF_FLAG);
+               }
+       }
+
        return (0);
 }
 
 int
 pfi_clear_flags(const char *name, int flags)
 {
-       struct pfi_kif  *p;
+       struct pfi_kif  *p, *w;
 
-       RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+       RB_FOREACH_SAFE(p, pfi_ifhead, &pfi_ifs, w) {
                if (pfi_skip_if(name, p))
                        continue;
+
+               KASSERT((p->pfik_flagrefs == 0) || (p->pfik_flagrefs == 1));
                p->pfik_flags_new = p->pfik_flags & ~flags;
+               if ((p->pfik_flags_new != p->pfik_flags) &&
+                   (p->pfik_flagrefs == 1))
+                       pfi_kif_unref(p, PFI_KIF_REF_FLAG);
        }
+
        return (0);
 }
 
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 514b9e156f3..61fb6b9436f 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1171,6 +1171,7 @@ struct pfi_kif {
        int                              pfik_rules;
        int                              pfik_routes;
        int                              pfik_srcnodes;
+       int                              pfik_flagrefs;
        TAILQ_HEAD(, pfi_dynaddr)        pfik_dynaddrs;
 };
 
@@ -1179,7 +1180,8 @@ enum pfi_kif_refs {
        PFI_KIF_REF_STATE,
        PFI_KIF_REF_RULE,
        PFI_KIF_REF_ROUTE,
-       PFI_KIF_REF_SRCNODE
+       PFI_KIF_REF_SRCNODE,
+       PFI_KIF_REF_FLAG
 };
 
 #define PFI_IFLAG_SKIP         0x0100  /* skip filtering on interface */
@@ -1867,8 +1869,8 @@ void               pfi_attach_ifnet(struct ifnet *);
 void            pfi_detach_ifnet(struct ifnet *);
 void            pfi_attach_ifgroup(struct ifg_group *);
 void            pfi_detach_ifgroup(struct ifg_group *);
-void            pfi_group_change(const char *);
 void            pfi_group_addmember(const char *, struct ifnet *);
+void            pfi_group_delmember(const char *, struct ifnet *);
 int             pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
                    sa_family_t);
 int             pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t);

Reply via email to