Module Name:    src
Committed By:   martin
Date:           Tue Mar 13 15:40:25 UTC 2018

Modified Files:
        src/sys/net [netbsd-8]: if_ethersubr.c

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #628):
        sys/net/if_ethersubr.c: revision 1.250
        sys/net/if_ethersubr.c: revision 1.251
        sys/net/if_ethersubr.c: revision 1.252
        sys/net/if_ethersubr.c: revision 1.248
Use kmem_alloc instead of kmem_intr_alloc in ether_addmulti

ether_addmulti is now not called in softint thanks to wqinput that
pulled input routines of ICMP out of softint.

style

Fix the net.ether.multicast sysctl. If there is no multicast address
don't kmem_alloc(0) (which panics the kernel), and if the number of
multicast addresses has decreased don't copyout uninitialized kernel
data.

Several fixes:
 - Style and typos
 - Use kmem_zalloc, in case there is a padding between the fields of
   the structures
 - Use ETHER_ADDR_LEN instead of a hard-coded '6'
 - kmem_alloc(KM_SLEEP) can't fail
 - Simplify ether_aton_r
 - Use mutex_obj_free, not to leak memory


To generate a diff of this commit:
cvs rdiff -u -r1.242.6.4 -r1.242.6.5 src/sys/net/if_ethersubr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.242.6.4 src/sys/net/if_ethersubr.c:1.242.6.5
--- src/sys/net/if_ethersubr.c:1.242.6.4	Thu Mar  8 14:37:58 2018
+++ src/sys/net/if_ethersubr.c	Tue Mar 13 15:40:25 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ethersubr.c,v 1.242.6.4 2018/03/08 14:37:58 martin Exp $	*/
+/*	$NetBSD: if_ethersubr.c,v 1.242.6.5 2018/03/13 15:40:25 martin Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.242.6.4 2018/03/08 14:37:58 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.242.6.5 2018/03/13 15:40:25 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -192,7 +192,7 @@ ether_output(struct ifnet * const ifp0, 
 {
 	uint16_t etype = 0;
 	int error = 0, hdrcmplt = 0;
- 	uint8_t esrc[6], edst[6];
+	uint8_t esrc[6], edst[6];
 	struct mbuf *m = m0;
 	struct mbuf *mcopy = NULL;
 	struct ether_header *eh;
@@ -301,7 +301,7 @@ ether_output(struct ifnet * const ifp0, 
 		break;
 #endif
 #ifdef NETATALK
-    case AF_APPLETALK: {
+	case AF_APPLETALK: {
 		struct ifaddr *ifa;
 		int s;
 
@@ -347,7 +347,7 @@ ether_output(struct ifnet * const ifp0, 
 		pserialize_read_exit(s);
 		KERNEL_UNLOCK_ONE(NULL);
 		break;
-	    }
+	}
 #endif /* NETATALK */
 	case pseudo_AF_HDRCMPLT:
 		hdrcmplt = 1;
@@ -357,7 +357,7 @@ ether_output(struct ifnet * const ifp0, 
 		/* FALLTHROUGH */
 
 	case AF_UNSPEC:
- 		memcpy(edst,
+		memcpy(edst,
 		    ((const struct ether_header *)dst->sa_data)->ether_dhost,
 		    sizeof(edst));
 		/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
@@ -401,7 +401,7 @@ ether_output(struct ifnet * const ifp0, 
 	eh = mtod(m, struct ether_header *);
 	/* Note: etype is already in network byte order. */
 	(void)memcpy(&eh->ether_type, &etype, sizeof(eh->ether_type));
- 	memcpy(eh->ether_dhost, edst, sizeof(edst));
+	memcpy(eh->ether_dhost, edst, sizeof(edst));
 	if (hdrcmplt)
 		memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost));
 	else
@@ -538,7 +538,7 @@ altq_etherclassify(struct ifaltq *ifq, s
 
 	return;
 
- bad:
+bad:
 	m->m_pkthdr.pattr_class = NULL;
 	m->m_pkthdr.pattr_hdr = NULL;
 	m->m_pkthdr.pattr_af = AF_UNSPEC;
@@ -579,7 +579,7 @@ ether_input(struct ifnet *ifp, struct mb
 	etype = ntohs(eh->ether_type);
 	ehlen = sizeof(*eh);
 
-	if(__predict_false(earlypkts < 100 || !rnd_initial_entropy)) {
+	if (__predict_false(earlypkts < 100 || !rnd_initial_entropy)) {
 		rnd_add_data(NULL, eh, ehlen, 0);
 		earlypkts++;
 	}
@@ -640,6 +640,7 @@ ether_input(struct ifnet *ifp, struct mb
 			return;
 	}
 #endif /* NCARP > 0 */
+
 	if ((m->m_flags & (M_BCAST | M_MCAST | M_PROMISC)) == 0 &&
 	    (ifp->if_flags & IFF_PROMISC) != 0 &&
 	    memcmp(CLLADDR(ifp->if_sadl), eh->ether_dhost,
@@ -695,7 +696,7 @@ ether_input(struct ifnet *ifp, struct mb
 		/*
 		 * If there is a tag of 0, then the VLAN header was probably
 		 * just being used to store the priority.  Extract the ether
-		 * type, and if IP or IPV6, let them deal with it. 
+		 * type, and if IP or IPV6, let them deal with it.
 		 */
 		if (m->m_len <= sizeof(*evl)
 		    && EVL_VLANOFTAG(evl->evl_tag) == 0) {
@@ -804,7 +805,7 @@ ether_input(struct ifnet *ifp, struct mb
 				m_freem(m);
 				return;
 			}
-#ifdef GATEWAY  
+#ifdef GATEWAY
 			if (ip6flow_fastforward(&m))
 				return;
 #endif
@@ -878,10 +879,10 @@ ether_input(struct ifnet *ifp, struct mb
 			m_freem(m);
 			return;
 		}
-#else /* ISO || LLC || NETATALK*/
+#else /* LLC || NETATALK */
 		m_freem(m);
 		return;
-#endif /* ISO || LLC || NETATALK*/
+#endif /* LLC || NETATALK */
 	}
 
 	if (__predict_true(pktq)) {
@@ -997,9 +998,7 @@ ether_ifdetach(struct ifnet *ifp)
 	if (ifp->if_bridge)
 		bridge_ifdetach(ifp);
 #endif
-
 	bpf_detach(ifp);
-
 #if NVLAN > 0
 	if (ec->ec_nvlans)
 		vlan_ifdetach(ifp);
@@ -1008,12 +1007,12 @@ ether_ifdetach(struct ifnet *ifp)
 	ETHER_LOCK(ec);
 	while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) {
 		LIST_REMOVE(enm, enm_list);
-		kmem_intr_free(enm, sizeof(*enm));
+		kmem_free(enm, sizeof(*enm));
 		ec->ec_multicnt--;
 	}
 	ETHER_UNLOCK(ec);
 
-	mutex_destroy(ec->ec_lock);
+	mutex_obj_free(ec->ec_lock);
 
 	ifp->if_mowner = NULL;
 	MOWNER_DETACH(&ec->ec_rx_mowner);
@@ -1113,7 +1112,7 @@ const uint8_t ether_ip6multicast_max[ETH
 int
 ether_aton_r(u_char *dest, size_t len, const char *str)
 {
-        const u_char *cp = (const void *)str;
+	const u_char *cp = (const void *)str;
 	u_char *ep;
 
 #define atox(c)	(((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10))
@@ -1122,20 +1121,22 @@ ether_aton_r(u_char *dest, size_t len, c
 		return ENOSPC;
 
 	ep = dest + ETHER_ADDR_LEN;
-	 
+
 	while (*cp) {
-                if (!isxdigit(*cp))
-                        return EINVAL;
+		if (!isxdigit(*cp))
+			return EINVAL;
+
 		*dest = atox(*cp);
 		cp++;
-                if (isxdigit(*cp)) {
-                        *dest = (*dest << 4) | atox(*cp);
-			dest++;
+		if (isxdigit(*cp)) {
+			*dest = (*dest << 4) | atox(*cp);
 			cp++;
-                } else
-			dest++;
+		}
+		dest++;
+
 		if (dest == ep)
-			return *cp == '\0' ? 0 : ENAMETOOLONG;
+			return (*cp == '\0') ? 0 : ENAMETOOLONG;
+
 		switch (*cp) {
 		case ':':
 		case '-':
@@ -1143,7 +1144,7 @@ ether_aton_r(u_char *dest, size_t len, c
 			cp++;
 			break;
 		}
-        }
+	}
 	return ENOBUFS;
 }
 
@@ -1181,8 +1182,7 @@ ether_multiaddr(const struct sockaddr *s
 			 */
 			memcpy(addrlo, ether_ipmulticast_min, ETHER_ADDR_LEN);
 			memcpy(addrhi, ether_ipmulticast_max, ETHER_ADDR_LEN);
-		}
-		else {
+		} else {
 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
 			memcpy(addrhi, addrlo, ETHER_ADDR_LEN);
 		}
@@ -1226,10 +1226,7 @@ ether_addmulti(const struct sockaddr *sa
 	int error = 0;
 
 	/* Allocate out of lock */
-	/* XXX still can be called in softint */
-	enm = kmem_intr_alloc(sizeof(*enm), KM_SLEEP);
-	if (enm == NULL)
-		return ENOBUFS;
+	enm = kmem_alloc(sizeof(*enm), KM_SLEEP);
 
 	ETHER_LOCK(ec);
 	error = ether_multiaddr(sa, addrlo, addrhi);
@@ -1243,6 +1240,7 @@ ether_addmulti(const struct sockaddr *sa
 		error = EINVAL;
 		goto out;
 	}
+
 	/*
 	 * See if the address range is already in the list.
 	 */
@@ -1255,24 +1253,27 @@ ether_addmulti(const struct sockaddr *sa
 		error = 0;
 		goto out;
 	}
+
 	/*
 	 * Link a new multicast record into the interface's multicast list.
 	 */
-	memcpy(enm->enm_addrlo, addrlo, 6);
-	memcpy(enm->enm_addrhi, addrhi, 6);
+	memcpy(enm->enm_addrlo, addrlo, ETHER_ADDR_LEN);
+	memcpy(enm->enm_addrhi, addrhi, ETHER_ADDR_LEN);
 	enm->enm_refcount = 1;
 	LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list);
 	ec->ec_multicnt++;
+
 	/*
 	 * Return ENETRESET to inform the driver that the list has changed
 	 * and its reception filter should be adjusted accordingly.
 	 */
 	error = ENETRESET;
 	enm = NULL;
+
 out:
 	ETHER_UNLOCK(ec);
 	if (enm != NULL)
-		kmem_intr_free(enm, sizeof(*enm));
+		kmem_free(enm, sizeof(*enm));
 	return error;
 }
 
@@ -1293,7 +1294,7 @@ ether_delmulti(const struct sockaddr *sa
 		goto error;
 
 	/*
-	 * Look ur the address in our list.
+	 * Look up the address in our list.
 	 */
 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm);
 	if (enm == NULL) {
@@ -1307,19 +1308,21 @@ ether_delmulti(const struct sockaddr *sa
 		error = 0;
 		goto error;
 	}
+
 	/*
 	 * No remaining claims to this record; unlink and free it.
 	 */
 	LIST_REMOVE(enm, enm_list);
 	ec->ec_multicnt--;
 	ETHER_UNLOCK(ec);
+	kmem_free(enm, sizeof(*enm));
 
-	kmem_intr_free(enm, sizeof(*enm));
 	/*
 	 * Return ENETRESET to inform the driver that the list has changed
 	 * and its reception filter should be adjusted accordingly.
 	 */
 	return ENETRESET;
+
 error:
 	ETHER_UNLOCK(ec);
 	return error;
@@ -1360,7 +1363,7 @@ ether_ioctl(struct ifnet *ifp, u_long cm
 #ifdef INET
 		if (ifa->ifa_addr->sa_family == AF_INET)
 			arp_ifinit(ifp, ifa);
-#endif /* INET */
+#endif
 		return 0;
 	    }
 
@@ -1502,7 +1505,7 @@ ether_disable_vlan_mtu(struct ifnet *ifp
 	 * Disable Tx/Rx of VLAN-sized frames.
 	 */
 	ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
-	
+
 	/* Interface is down, defer for later */
 	if ((ifp->if_flags & IFF_UP) == 0)
 		return 0;
@@ -1552,16 +1555,23 @@ ether_multicast_sysctl(SYSCTLFN_ARGS)
 
 	/*
 	 * ec->ec_lock is a spin mutex so we cannot call sysctl_copyout, which
-	 * is sleepable, with holding it. Copy data to a local buffer first
-	 * with holding it and then call sysctl_copyout without holding it.
+	 * is sleepable, while holding it. Copy data to a local buffer first
+	 * with the lock taken and then call sysctl_copyout without holding it.
 	 */
 retry:
 	multicnt = ec->ec_multicnt;
-	addrs = kmem_alloc(sizeof(*addrs) * multicnt, KM_SLEEP);
+
+	if (multicnt == 0) {
+		if_put(ifp, &psref);
+		*oldlenp = 0;
+		goto out;
+	}
+
+	addrs = kmem_zalloc(sizeof(*addrs) * multicnt, KM_SLEEP);
 
 	ETHER_LOCK(ec);
-	if (multicnt < ec->ec_multicnt) {
-		/* The number of multicast addresses have increased */
+	if (multicnt != ec->ec_multicnt) {
+		/* The number of multicast addresses has changed */
 		ETHER_UNLOCK(ec);
 		kmem_free(addrs, sizeof(*addrs) * multicnt);
 		goto retry;

Reply via email to