On Wed, Dec 27, 2017 at 04:55:49PM +0100, Martin Pieuchot wrote:
> Updated diff below.
OK bluhm@
> Index: net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.531
> diff -u -p -r1.531 if.c
> --- net/if.c 15 Dec 2017 01:37:30 -0000 1.531
> +++ net/if.c 27 Dec 2017 15:54:18 -0000
> @@ -1854,13 +1854,12 @@ ifioctl(struct socket *so, u_long cmd, c
> oif_flags = ifp->if_flags;
> oif_xflags = ifp->if_xflags;
>
> - NET_LOCK();
> -
> switch (cmd) {
> case SIOCIFAFATTACH:
> case SIOCIFAFDETACH:
> if ((error = suser(p, 0)) != 0)
> break;
> + NET_LOCK();
> switch (ifar->ifar_af) {
> case AF_INET:
> /* attach is a noop for AF_INET */
> @@ -1878,22 +1877,21 @@ ifioctl(struct socket *so, u_long cmd, c
> default:
> error = EAFNOSUPPORT;
> }
> + NET_UNLOCK();
> break;
>
> case SIOCSIFFLAGS:
> if ((error = suser(p, 0)) != 0)
> break;
>
> + NET_LOCK();
> ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
> (ifr->ifr_flags & ~IFF_CANTCHANGE);
>
> error = (*ifp->if_ioctl)(ifp, cmd, data);
> if (error != 0) {
> ifp->if_flags = oif_flags;
> - break;
> - }
> -
> - if (ISSET(oif_flags ^ ifp->if_flags, IFF_UP)) {
> + } else if (ISSET(oif_flags ^ ifp->if_flags, IFF_UP)) {
> s = splnet();
> if (ISSET(ifp->if_flags, IFF_UP))
> if_up(ifp);
> @@ -1901,17 +1899,21 @@ ifioctl(struct socket *so, u_long cmd, c
> if_down(ifp);
> splx(s);
> }
> + NET_UNLOCK();
> break;
>
> case SIOCSIFXFLAGS:
> if ((error = suser(p, 0)) != 0)
> break;
>
> + NET_LOCK();
> #ifdef INET6
> if (ISSET(ifr->ifr_flags, IFXF_AUTOCONF6)) {
> error = in6_ifattach(ifp);
> - if (error != 0)
> + if (error != 0) {
> + NET_UNLOCK();
> break;
> + }
> }
> #endif /* INET6 */
>
> @@ -1942,8 +1944,6 @@ ifioctl(struct socket *so, u_long cmd, c
> ifp->if_xflags |= IFXF_WOL;
> error = ifp->if_wol(ifp, 1);
> splx(s);
> - if (error)
> - break;
> }
> if (ISSET(ifp->if_xflags, IFXF_WOL) &&
> !ISSET(ifr->ifr_flags, IFXF_WOL)) {
> @@ -1951,8 +1951,6 @@ ifioctl(struct socket *so, u_long cmd, c
> ifp->if_xflags &= ~IFXF_WOL;
> error = ifp->if_wol(ifp, 0);
> splx(s);
> - if (error)
> - break;
> }
> } else if (ISSET(ifr->ifr_flags, IFXF_WOL)) {
> ifr->ifr_flags &= ~IFXF_WOL;
> @@ -1960,20 +1958,26 @@ ifioctl(struct socket *so, u_long cmd, c
> }
> #endif
>
> - ifp->if_xflags = (ifp->if_xflags & IFXF_CANTCHANGE) |
> - (ifr->ifr_flags & ~IFXF_CANTCHANGE);
> + if (error == 0)
> + ifp->if_xflags = (ifp->if_xflags & IFXF_CANTCHANGE) |
> + (ifr->ifr_flags & ~IFXF_CANTCHANGE);
> + NET_UNLOCK();
> break;
>
> case SIOCSIFMETRIC:
> if ((error = suser(p, 0)) != 0)
> break;
> + NET_LOCK();
> ifp->if_metric = ifr->ifr_metric;
> + NET_UNLOCK();
> break;
>
> case SIOCSIFMTU:
> if ((error = suser(p, 0)) != 0)
> break;
> + NET_LOCK();
> error = (*ifp->if_ioctl)(ifp, cmd, data);
> + NET_UNLOCK();
> if (!error)
> rtm_ifchg(ifp);
> break;
> @@ -2013,27 +2017,34 @@ ifioctl(struct socket *so, u_long cmd, c
> case SIOCSIFRDOMAIN:
> if ((error = suser(p, 0)) != 0)
> break;
> + NET_LOCK();
> error = if_setrdomain(ifp, ifr->ifr_rdomainid);
> + NET_UNLOCK();
> break;
>
> case SIOCAIFGROUP:
> if ((error = suser(p, 0)))
> break;
> - if ((error = if_addgroup(ifp, ifgr->ifgr_group)))
> - break;
> - error = (*ifp->if_ioctl)(ifp, cmd, data);
> - if (error == ENOTTY)
> - error = 0;
> + NET_LOCK();
> + error = if_addgroup(ifp, ifgr->ifgr_group);
> + if (error == 0) {
> + error = (*ifp->if_ioctl)(ifp, cmd, data);
> + if (error == ENOTTY)
> + error = 0;
> + }
> + NET_UNLOCK();
> break;
>
> case SIOCDIFGROUP:
> if ((error = suser(p, 0)))
> break;
> + NET_LOCK();
> error = (*ifp->if_ioctl)(ifp, cmd, data);
> if (error == ENOTTY)
> error = 0;
> if (error == 0)
> error = if_delgroup(ifp, ifgr->ifgr_group);
> + NET_UNLOCK();
> break;
>
> case SIOCSIFLLADDR:
> @@ -2045,6 +2056,7 @@ ifioctl(struct socket *so, u_long cmd, c
> error = EINVAL;
> break;
> }
> + NET_LOCK();
> switch (ifp->if_type) {
> case IFT_ETHER:
> case IFT_CARP:
> @@ -2063,6 +2075,7 @@ ifioctl(struct socket *so, u_long cmd, c
>
> if (error == 0)
> ifnewlladdr(ifp);
> + NET_UNLOCK();
> break;
>
> case SIOCSIFLLPRIO:
> @@ -2072,7 +2085,9 @@ ifioctl(struct socket *so, u_long cmd, c
> error = EINVAL;
> break;
> }
> + NET_LOCK();
> ifp->if_llprio = ifr->ifr_llprio;
> + NET_UNLOCK();
> break;
>
> case SIOCDIFPHYADDR:
> @@ -2090,11 +2105,13 @@ ifioctl(struct socket *so, u_long cmd, c
> break;
> /* FALLTHROUGH */
> default:
> + NET_LOCK();
> error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
> (struct mbuf *) cmd, (struct mbuf *) data,
> (struct mbuf *) ifp, p));
> if (error == EOPNOTSUPP)
> error = ((*ifp->if_ioctl)(ifp, cmd, data));
> + NET_UNLOCK();
> break;
> }
>
> @@ -2103,8 +2120,6 @@ ifioctl(struct socket *so, u_long cmd, c
>
> if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0)
> getmicrotime(&ifp->if_lastchange);
> -
> - NET_UNLOCK();
>
> return (error);
> }
> Index: net/if_var.h
> ===================================================================
> RCS file: /cvs/src/sys/net/if_var.h,v
> retrieving revision 1.85
> diff -u -p -r1.85 if_var.h
> --- net/if_var.h 15 Dec 2017 01:37:30 -0000 1.85
> +++ net/if_var.h 27 Dec 2017 15:39:36 -0000
> @@ -91,7 +91,14 @@ struct if_clone {
>
> #define IF_CLONE_INITIALIZER(name, create, destroy)
> \
> { { 0 }, name, sizeof(name) - 1, create, destroy }
> -
> +/*
> + * Locks used to protect struct members in this file:
> + * I immutable after creation
> + * d protection left do the driver
> + * c only used in ioctl or routing socket contexts (kernel lock)
> + * k kernel lock
> + * N net lock
> + */
> /*
> * Structure defining a queue for a network interface.
> *
> @@ -102,17 +109,17 @@ TAILQ_HEAD(ifnet_head, ifnet); /* the a
> struct ifnet { /* and the entries */
> void *if_softc; /* lower-level data for this if */
> struct refcnt if_refcnt;
> - TAILQ_ENTRY(ifnet) if_list; /* all struct ifnets are chained */
> - TAILQ_HEAD(, ifaddr) if_addrlist; /* linked list of addresses per if */
> - TAILQ_HEAD(, ifmaddr) if_maddrlist; /* list of multicast records */
> - TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
> - struct hook_desc_head *if_addrhooks; /* address change callbacks */
> - struct hook_desc_head *if_linkstatehooks; /* link change callbacks */
> - struct hook_desc_head *if_detachhooks; /* detach callbacks */
> - /* check or clean routes (+ or -)'d */
> + TAILQ_ENTRY(ifnet) if_list; /* [k] all struct ifnets are chained */
> + TAILQ_HEAD(, ifaddr) if_addrlist; /* [N] list of addresses per if */
> + TAILQ_HEAD(, ifmaddr) if_maddrlist; /* [N] list of multicast records */
> + TAILQ_HEAD(, ifg_list) if_groups; /* [N] list of groups per if */
> + struct hook_desc_head *if_addrhooks; /* [I] address change callbacks */
> + struct hook_desc_head *if_linkstatehooks; /* [I] link change callbacks*/
> + struct hook_desc_head *if_detachhooks; /* [I] detach callbacks */
> + /* [I] check or clean routes (+ or -)'d */
> void (*if_rtrequest)(struct ifnet *, int, struct rtentry *);
> - char if_xname[IFNAMSIZ]; /* external name (name + unit) */
> - int if_pcount; /* number of promiscuous listeners */
> + char if_xname[IFNAMSIZ]; /* [I] external name (name + unit) */
> + int if_pcount; /* [k] # of promiscuous listeners */
> caddr_t if_bpf; /* packet filter structure */
> caddr_t if_bridgeport; /* used by bridge ports */
> caddr_t if_switchport; /* used by switch ports */
> @@ -125,48 +132,43 @@ struct ifnet { /* and the
> entries */
> } if_carp_ptr;
> #define if_carp if_carp_ptr.carp_s
> #define if_carpdev if_carp_ptr.carp_d
> - unsigned int if_index; /* numeric abbreviation for this if */
> + unsigned int if_index; /* [I] unique index for this if */
> short if_timer; /* time 'til if_watchdog called */
> - unsigned short if_flags; /* up/down, broadcast, etc. */
> - int if_xflags; /* extra softnet flags */
> + unsigned short if_flags; /* [N] up/down, broadcast, etc. */
> + int if_xflags; /* [N] extra softnet flags */
> struct if_data if_data; /* stats and other data about if */
> - u_int32_t if_hardmtu; /* maximum MTU device supports */
> - char if_description[IFDESCRSIZE]; /* interface description */
> - u_short if_rtlabelid; /* next route label */
> - u_int8_t if_priority;
> - u_int8_t if_llprio; /* link layer priority */
> - struct timeout *if_slowtimo; /* watchdog timeout */
> - struct task *if_watchdogtask; /* watchdog task */
> - struct task *if_linkstatetask; /* task to do route updates */
> + uint32_t if_hardmtu; /* [d] maximum MTU device supports */
> + char if_description[IFDESCRSIZE]; /* [c] interface description */
> + u_short if_rtlabelid; /* [c] next route label */
> + uint8_t if_priority; /* [c] route priority offset */
> + uint8_t if_llprio; /* [N] link layer priority */
> + struct timeout *if_slowtimo; /* [I] watchdog timeout */
> + struct task *if_watchdogtask; /* [I] watchdog task */
> + struct task *if_linkstatetask; /* [I] task to do route updates */
>
> /* procedure handles */
> SRPL_HEAD(, ifih) if_inputs; /* input routines (dequeue) */
> -
> - /* output routine (enqueue) */
> int (*if_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
> - struct rtentry *);
> -
> + struct rtentry *); /* output routine (enqueue) */
> /* link level output function */
> int (*if_ll_output)(struct ifnet *, struct mbuf *,
> struct sockaddr *, struct rtentry *);
> - /* initiate output routine */
> - void (*if_start)(struct ifnet *);
> - /* ioctl routine */
> - int (*if_ioctl)(struct ifnet *, u_long, caddr_t);
> - /* timer routine */
> - void (*if_watchdog)(struct ifnet *);
> - int (*if_wol)(struct ifnet *, int);
> + void (*if_start)(struct ifnet *); /* initiate output */
> + int (*if_ioctl)(struct ifnet *, u_long, caddr_t); /* ioctl hook */
> + void (*if_watchdog)(struct ifnet *); /* timer routine */
> + int (*if_wol)(struct ifnet *, int); /* WoL routine **/
>
> + /* queues */
> struct ifqueue if_snd; /* transmit queue */
> - struct ifqueue **if_ifqs; /* pointer to an array of sndqs */
> + struct ifqueue **if_ifqs; /* [I] pointer to an array of sndqs */
> void (*if_qstart)(struct ifqueue *);
> - unsigned int if_nifqs;
> + unsigned int if_nifqs; /* [I] number of output queues */
>
> struct ifiqueue if_rcv; /* rx/input queue */
> - struct ifiqueue **if_iqs; /* pointer to the array of iqs */
> - unsigned int if_niqs;
> + struct ifiqueue **if_iqs; /* [I] pointer to the array of iqs */
> + unsigned int if_niqs; /* [I] number of input queues */
>
> - struct sockaddr_dl *if_sadl; /* pointer to our sockaddr_dl */
> + struct sockaddr_dl *if_sadl; /* [N] pointer to our sockaddr_dl */
>
> void *if_afdata[AF_MAX];
> };
> @@ -189,7 +191,7 @@ struct ifnet { /* and the
> entries */
> #define if_iqdrops if_data.ifi_iqdrops
> #define if_oqdrops if_data.ifi_oqdrops
> #define if_noproto if_data.ifi_noproto
> -#define if_lastchange if_data.ifi_lastchange
> +#define if_lastchange if_data.ifi_lastchange /* [c] last op. state
> change */
> #define if_capabilities if_data.ifi_capabilities
> #define if_rdomain if_data.ifi_rdomain
>