Tue Mar 13 15:40:25 2018 UTC ()
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


(martin)
diff -r1.242.6.4 -r1.242.6.5 src/sys/net/if_ethersubr.c

cvs diff -r1.242.6.4 -r1.242.6.5 src/sys/net/if_ethersubr.c (expand / switch to context diff)
--- src/sys/net/if_ethersubr.c 2018/03/08 14:37:58 1.242.6.4
+++ src/sys/net/if_ethersubr.c 2018/03/13 15:40:25 1.242.6.5
@@ -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 @@
 {
 	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 @@
 		break;
 #endif
 #ifdef NETATALK
-    case AF_APPLETALK: {
+	case AF_APPLETALK: {
 		struct ifaddr *ifa;
 		int s;
 
@@ -347,7 +347,7 @@
 		pserialize_read_exit(s);
 		KERNEL_UNLOCK_ONE(NULL);
 		break;
-	    }
+	}
 #endif /* NETATALK */
 	case pseudo_AF_HDRCMPLT:
 		hdrcmplt = 1;
@@ -357,7 +357,7 @@
 		/* 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 @@
 	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 @@
 
 	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 @@
 	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 @@
 			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 @@
 		/*
 		 * 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 @@
 				m_freem(m);
 				return;
 			}
-#ifdef GATEWAY  
+#ifdef GATEWAY
 			if (ip6flow_fastforward(&m))
 				return;
 #endif
@@ -878,10 +879,10 @@
 			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 @@
 	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_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 @@
 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 @@
 		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 @@
 			cp++;
 			break;
 		}
-        }
+	}
 	return ENOBUFS;
 }
 
@@ -1181,8 +1182,7 @@
 			 */
 			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 @@
 	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 @@
 		error = EINVAL;
 		goto out;
 	}
+
 	/*
 	 * See if the address range is already in the list.
 	 */
@@ -1255,24 +1253,27 @@
 		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 @@
 		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 @@
 		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 @@
 #ifdef INET
 		if (ifa->ifa_addr->sa_family == AF_INET)
 			arp_ifinit(ifp, ifa);
-#endif /* INET */
+#endif
 		return 0;
 	    }
 
@@ -1502,7 +1505,7 @@
 	 * 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 @@
 
 	/*
 	 * 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;