changeset 13107:eb7af425d949

PSARC/2010/159 SIOCGIFHWADDR for PF_INET and PF_INET6 6948284 setsockopt on PF_PACKET socket fails for PACKET_MR_PROMISC option 6948282 missing definitions in the packet.h header file 4720634 programmatic access to mac address for non-root applications
author Darren Reed <Darren.Reed@Oracle.COM>
date Thu, 12 Aug 2010 16:05:23 -0700
parents efddb0166961
children b02331b7b26d
files usr/src/cmd/truss/codes.c usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip_arp.c usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/inet/ip_arp.h usr/src/uts/common/inet/ip_if.h usr/src/uts/common/inet/sockmods/netpacket/packet.h usr/src/uts/common/inet/sockmods/sockmod_pfp.c usr/src/uts/common/net/if_arp.h usr/src/uts/common/sys/sockio.h usr/src/uts/intel/sockpfp/Makefile usr/src/uts/sparc/sockpfp/Makefile
diffstat 12 files changed, 271 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/truss/codes.c	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/cmd/truss/codes.c	Thu Aug 12 16:05:23 2010 -0700
@@ -878,6 +878,9 @@
 	{ (uint_t)SIOCSIPMSFILTER,	"SIOCSIPMSFILTER",  "ip_msfilter" },
 	{ (uint_t)SIOCGLIFDADSTATE,	"SIOCGLIFDADSTATE",  "lifreq" },
 	{ (uint_t)SIOCSLIFPREFIX,	"SIOCSLIFPREFIX", "lifreq" },
+	{ (uint_t)SIOCGSTAMP,		"SIOCGSTAMP",		"timeval" },
+	{ (uint_t)SIOCGIFHWADDR,	"SIOCGIFHWADDR",	"ifreq" },
+	{ (uint_t)SIOCGLIFHWADDR,	"SIOCGLIFHWADDR",	"lifreq" },
 
 	/* DES encryption */
 	{ (uint_t)DESIOCBLOCK,	"DESIOCBLOCK", 	"desparams" },
--- a/usr/src/uts/common/inet/ip/ip.c	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/ip/ip.c	Thu Aug 12 16:05:23 2010 -0700
@@ -1101,7 +1101,8 @@
 	/* SIOCSENABLESDP is handled by SDP */
 	/* 183 */ { IPI_DONTCARE /* SIOCSENABLESDP */, 0, 0, 0, NULL, NULL },
 	/* 184 */ { IPI_DONTCARE /* SIOCSQPTR */, 0, 0, 0, NULL, NULL },
-	/* 185 */ { IPI_DONTCARE /* SIOCGIFHWADDR */, 0, 0, 0, NULL, NULL },
+	/* 185 */ { SIOCGIFHWADDR, sizeof (struct ifreq), IPI_GET_CMD,
+			IF_CMD, ip_sioctl_get_ifhwaddr, NULL },
 	/* 186 */ { IPI_DONTCARE /* SIOCGSTAMP */, 0, 0, 0, NULL, NULL },
 	/* 187 */ { SIOCILB, 0, IPI_PRIV | IPI_GET_CMD, MISC_CMD,
 			ip_sioctl_ilb_cmd, NULL },
@@ -1110,7 +1111,9 @@
 	/* 190 */ { SIOCGLIFDADSTATE, sizeof (struct lifreq),
 			IPI_GET_CMD, LIF_CMD, ip_sioctl_get_dadstate, NULL },
 	/* 191 */ { SIOCSLIFPREFIX, sizeof (struct lifreq), IPI_PRIV | IPI_WR,
-			LIF_CMD, ip_sioctl_prefix, ip_sioctl_prefix_restart }
+			LIF_CMD, ip_sioctl_prefix, ip_sioctl_prefix_restart },
+	/* 192 */ { SIOCGLIFHWADDR, sizeof (struct lifreq), IPI_GET_CMD,
+			LIF_CMD, ip_sioctl_get_lifhwaddr, NULL }
 };
 
 int ip_ndx_ioctl_count = sizeof (ip_ndx_ioctl_table) / sizeof (ip_ioctl_cmd_t);
--- a/usr/src/uts/common/inet/ip/ip_arp.c	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/ip/ip_arp.c	Thu Aug 12 16:05:23 2010 -0700
@@ -355,7 +355,7 @@
 	return (NULL);
 }
 
-static uint32_t
+uint32_t
 arp_hw_type(t_uscalar_t mactype)
 {
 	arp_m_t *arm;
--- a/usr/src/uts/common/inet/ip/ip_if.c	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Thu Aug 12 16:05:23 2010 -0700
@@ -19042,3 +19042,114 @@
 	rw_exit(&ipst->ips_ill_g_usesrc_lock);
 	return (ill);
 }
+
+/*
+ * This comment applies to both ip_sioctl_get_ifhwaddr and
+ * ip_sioctl_get_lifhwaddr as the basic function of these two functions
+ * is the same.
+ *
+ * The goal here is to find an IP interface that corresponds to the name
+ * provided by the caller in the ifreq/lifreq structure held in the mblk_t
+ * chain and to fill out a sockaddr/sockaddr_storage structure with the
+ * mac address.
+ *
+ * The SIOCGIFHWADDR/SIOCGLIFHWADDR ioctl may return an error for a number
+ * of different reasons:
+ * ENXIO - the device name is not known to IP.
+ * EADDRNOTAVAIL - the device has no hardware address. This is indicated
+ * by ill_phys_addr not pointing to an actual address.
+ * EPFNOSUPPORT - this will indicate that a request is being made for a
+ * mac address that will not fit in the data structure supplier (struct
+ * sockaddr).
+ *
+ */
+/* ARGSUSED */
+int
+ip_sioctl_get_ifhwaddr(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp,
+    ip_ioctl_cmd_t *ipip, void *if_req)
+{
+	struct sockaddr *sock;
+	struct ifreq *ifr;
+	mblk_t *mp1;
+	ill_t *ill;
+
+	ASSERT(ipif != NULL);
+	ill = ipif->ipif_ill;
+
+	if (ill->ill_phys_addr == NULL) {
+		return (EADDRNOTAVAIL);
+	}
+	if (ill->ill_phys_addr_length > sizeof (sock->sa_data)) {
+		return (EPFNOSUPPORT);
+	}
+
+	ip1dbg(("ip_sioctl_get_hwaddr(%s)\n", ill->ill_name));
+
+	/* Existence of mp1 has been checked in ip_wput_nondata */
+	mp1 = mp->b_cont->b_cont;
+	ifr = (struct ifreq *)mp1->b_rptr;
+
+	sock = &ifr->ifr_addr;
+	/*
+	 * The "family" field in the returned structure is set to a value
+	 * that represents the type of device to which the address belongs.
+	 * The value returned may differ to that on Linux but it will still
+	 * represent the correct symbol on Solaris.
+	 */
+	sock->sa_family = arp_hw_type(ill->ill_mactype);
+	bcopy(ill->ill_phys_addr, &sock->sa_data, ill->ill_phys_addr_length);
+
+	return (0);
+}
+
+/*
+ * The expection of applications using SIOCGIFHWADDR is that data will
+ * be returned in the sa_data field of the sockaddr structure. With
+ * SIOCGLIFHWADDR, we're breaking new ground as there is no Linux
+ * equivalent. In light of this, struct sockaddr_dl is used as it
+ * offers more space for address storage in sll_data.
+ */
+/* ARGSUSED */
+int
+ip_sioctl_get_lifhwaddr(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp,
+    ip_ioctl_cmd_t *ipip, void *if_req)
+{
+	struct sockaddr_dl *sock;
+	struct lifreq *lifr;
+	mblk_t *mp1;
+	ill_t *ill;
+
+	ASSERT(ipif != NULL);
+	ill = ipif->ipif_ill;
+
+	if (ill->ill_phys_addr == NULL) {
+		return (EADDRNOTAVAIL);
+	}
+	if (ill->ill_phys_addr_length > sizeof (sock->sdl_data)) {
+		return (EPFNOSUPPORT);
+	}
+
+	ip1dbg(("ip_sioctl_get_lifhwaddr(%s)\n", ill->ill_name));
+
+	/* Existence of mp1 has been checked in ip_wput_nondata */
+	mp1 = mp->b_cont->b_cont;
+	lifr = (struct lifreq *)mp1->b_rptr;
+
+	/*
+	 * sockaddr_ll is used here because it is also the structure used in
+	 * responding to the same ioctl in sockpfp. The only other choice is
+	 * sockaddr_dl which contains fields that are not required here
+	 * because its purpose is different.
+	 */
+	lifr->lifr_type = ill->ill_type;
+	sock = (struct sockaddr_dl *)&lifr->lifr_addr;
+	sock->sdl_family = AF_LINK;
+	sock->sdl_index = ill->ill_phyint->phyint_ifindex;
+	sock->sdl_type = ill->ill_mactype;
+	sock->sdl_nlen = 0;
+	sock->sdl_slen = 0;
+	sock->sdl_alen = ill->ill_phys_addr_length;
+	bcopy(ill->ill_phys_addr, sock->sdl_data, ill->ill_phys_addr_length);
+
+	return (0);
+}
--- a/usr/src/uts/common/inet/ip_arp.h	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/ip_arp.h	Thu Aug 12 16:05:23 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _IP_ARP_H
@@ -115,6 +114,7 @@
 extern	void		arp_send_replumb_conf(ill_t *);
 extern	void		arp_unbind_complete(ill_t *);
 extern  ill_t		*arl_to_ill(arl_t *);
+extern	uint32_t	arp_hw_type(t_uscalar_t);
 #endif
 
 #define	ARP_RETRANS_TIMER	500 /* time in milliseconds */
--- a/usr/src/uts/common/inet/ip_if.h	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/ip_if.h	Thu Aug 12 16:05:23 2010 -0700
@@ -479,6 +479,11 @@
 extern int ip_sioctl_get_dadstate(ipif_t *, sin_t *, queue_t *, mblk_t *,
     ip_ioctl_cmd_t *, void *);
 
+extern int ip_sioctl_get_ifhwaddr(ipif_t *, sin_t *, queue_t *, mblk_t *,
+    ip_ioctl_cmd_t *, void *);
+extern int ip_sioctl_get_lifhwaddr(ipif_t *, sin_t *, queue_t *, mblk_t *,
+    ip_ioctl_cmd_t *, void *);
+
 extern	void	ip_sioctl_copyin_resume(ipsq_t *, queue_t *, mblk_t *, void *);
 extern	void	ip_sioctl_copyin_setup(queue_t *, mblk_t *);
 extern	ip_ioctl_cmd_t *ip_sioctl_lookup(int);
--- a/usr/src/uts/common/inet/sockmods/netpacket/packet.h	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/sockmods/netpacket/packet.h	Thu Aug 12 16:05:23 2010 -0700
@@ -20,14 +20,14 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _PACKET_H
 #define	_PACKET_H
 
 #include <sys/socket_impl.h>
+#include <net/if_arp.h>
 #include <net/bpf.h>
 
 /*
@@ -116,26 +116,25 @@
  *
  * The numbers above 50000 are because their real value is unknown from
  * libpcap's source, so a number has been chosen that is unlikely to be
- * confused with the real one on Linux.
+ * confused with the real one on Linux. Those that are already found in
+ * Solaris inside <net/if_arp.h> may have a different value to that found
+ * in Linux but it should be used instead as the Solaris value originates
+ * from the IANA whereas the Linux values seem to ignore it.
  */
-#define	ARPHRD_ADAPT			50001
-#define	ARPHRD_ARCNET			50002
-#define	ARPHRD_ATM			19
-#define	ARPHRD_AX25			50003
-#define	ARPHRD_CHAOS			50004
-#define	ARPHRD_CISCO			513
+/* ARPHRD_AX25				see <net/if_arp.h> */
+/* ARPHRD_CHAOS				see <net/if_arp.h> */
 #define	ARPHRD_CSLIP			50005
 #define	ARPHRD_CSLIP6			50006
 #define	ARPHRD_DLCI			15
-#define	ARPHRD_EETHER			50007
-#define	ARPHRD_ETHER			50008
+/* ARPHRD_EETHER			see <net/if_arp.h> */
+/* ARPHRD_ETHER				see <net/if_arp.h> */
 #define	ARPHRD_FCAL			785
 #define	ARPHRD_FCFABRIC			787
 #define	ARPHRD_FCPL			786
 #define	ARPHRD_FCPP			784
 #define	ARPHRD_FRAD			770
 #define	ARPHRD_FDDI			774
-#define	ARPHRD_IEEE802			50009
+/* ARPHRD_IEEE802			see <net/if_arp.h> */
 #define	ARPHRD_IEEE802_TR		800
 #define	ARPHRD_IEEE80211		801
 #define	ARPHRD_IEEE80211_PRISM		802
@@ -144,14 +143,21 @@
 #define	ARPHRD_LAPD			8445
 #define	ARPHRD_LOCALTLK			50010
 #define	ARPHRD_LOOPBACK			50011
-#define	ARPHRD_METRICOM			50012
+/* ARPHRD_METRICOM			see <net/if_arp.h> */
 #define	ARPHRD_PRONET			50013
 #define	ARPHRD_PPP			50014
 #define	ARPHRD_RAWHDLC			518
 #define	ARPHRD_SIT			776
 #define	ARPHRD_SLIP6			50015
 #define	ARPHRD_SLIP			50016
-#define	ARPHRD_TUNNEL			50017
+/* ARPHRD_TUNNEL			see <net/if_arp.h> */
+
+#define	ETH_P_ALL			0
+#define	ETH_P_802_2			0xaa	/* LSAP_SAP */
+#define	ETH_P_803_3			0
+#define	ETH_P_IP			0x800
+#define	ETH_P_ARP			0x806
+#define	ETH_P_IPV6			0x86dd
 
 #ifdef _KERNEL
 /*
--- a/usr/src/uts/common/inet/sockmods/sockmod_pfp.c	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/inet/sockmods/sockmod_pfp.c	Thu Aug 12 16:05:23 2010 -0700
@@ -39,8 +39,11 @@
 #include <sys/tihdr.h>
 #include <sys/zone.h>
 #include <sys/time.h>
+#include <sys/ethernet.h>
+#include <sys/llc1.h>
 #include <fs/sockfs/sockcommon.h>
 #include <net/if.h>
+#include <inet/ip_arp.h>
 
 #include <sys/dls.h>
 #include <sys/mac.h>
@@ -151,6 +154,12 @@
 	NULL
 };
 
+static int accepted_protos[3][2] = {
+	{ ETH_P_ALL,	0 },
+	{ ETH_P_802_2,	LLC_SNAP_SAP },
+	{ ETH_P_803_3,	0 },
+};
+
 /*
  * Module linkage information for the kernel.
  */
@@ -252,6 +261,8 @@
 {
 	struct pfpsock *ps;
 	int kmflags;
+	int newproto;
+	int i;
 
 	if (secpolicy_net_rawaccess(cred) != 0) {
 		*errorp = EACCES;
@@ -268,6 +279,33 @@
 		return (NULL);
 	}
 
+	/*
+	 * First check to see if the protocol number passed in via the socket
+	 * creation should be mapped to a different number for internal use.
+	 */
+	for (i = 0, newproto = -1;
+	    i < sizeof (accepted_protos)/ sizeof (accepted_protos[0]); i++) {
+		if (accepted_protos[i][0] == proto) {
+			newproto = accepted_protos[i][1];
+			break;
+		}
+	}
+
+	/*
+	 * If the mapping of the protocol that was under 0x800 failed to find
+	 * a local equivalent then fail the socket creation. If the protocol
+	 * for the socket is over 0x800 and it was not found in the mapping
+	 * table above, then use the value as is.
+	 */
+	if (newproto == -1) {
+		if (proto < 0x800) {
+			*errorp = ENOPROTOOPT;
+			return (NULL);
+		}
+		newproto = proto;
+	}
+	proto = newproto;
+
 	kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
 	ps = kmem_zalloc(sizeof (*ps), kmflags);
 	if (ps == NULL) {
@@ -838,6 +876,7 @@
 	struct timeval tival;
 #endif
 	mac_client_promisc_type_t mtype;
+	struct sockaddr_dl *sock;
 	datalink_id_t linkid;
 	struct lifreq lifreq;
 	struct ifreq ifreq;
@@ -854,6 +893,7 @@
 	case SIOCGLIFINDEX :
 	case SIOCGLIFFLAGS :
 	case SIOCGLIFMTU :
+	case SIOCGLIFHWADDR :
 		error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid);
 		if (error != 0)
 			return (error);
@@ -936,10 +976,56 @@
 		break;
 
 	case SIOCGIFHWADDR :
-		mac_unicast_primary_get(mh, (uint8_t *)ifreq.ifr_addr.sa_data);
+		if (mac_addr_len(mh) > sizeof (ifreq.ifr_addr.sa_data)) {
+			error = EPFNOSUPPORT;
+			break;
+		}
+
+		if (mac_addr_len(mh) == 0) {
+			(void) memset(ifreq.ifr_addr.sa_data, 0,
+			    sizeof (ifreq.ifr_addr.sa_data));
+		} else {
+			mac_unicast_primary_get(mh,
+			    (uint8_t *)ifreq.ifr_addr.sa_data);
+		}
+
+		/*
+		 * The behaviour here in setting sa_family is consistent
+		 * with what applications such as tcpdump would expect
+		 * for a Linux PF_PACKET socket.
+		 */
 		ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh));
 		break;
 
+	case SIOCGLIFHWADDR :
+		lifreq.lifr_type = 0;
+		sock = (struct sockaddr_dl *)&lifreq.lifr_addr;
+
+		if (mac_addr_len(mh) > sizeof (sock->sdl_data)) {
+			error = EPFNOSUPPORT;
+			break;
+		}
+
+		/*
+		 * Fill in the sockaddr_dl with link layer details. Of note,
+		 * the index is returned as 0 for a couple of reasons:
+		 * (1) there is no public API that uses or requires it
+		 * (2) the MAC index is currently 32bits and sdl_index is 16.
+		 */
+		sock->sdl_family = AF_LINK;
+		sock->sdl_index = 0;
+		sock->sdl_type = mac_type(mh);
+		sock->sdl_nlen = 0;
+		sock->sdl_alen = mac_addr_len(mh);
+		sock->sdl_slen = 0;
+		if (mac_addr_len(mh) == 0) {
+			(void) memset(sock->sdl_data, 0,
+			    sizeof (sock->sdl_data));
+		} else {
+			mac_unicast_primary_get(mh, (uint8_t *)sock->sdl_data);
+		}
+		break;
+
 	case SIOCGSTAMP :
 		(void) gethrestime(&tv);
 		tival.tv_sec = (time_t)tv.tv_sec;
@@ -961,6 +1047,7 @@
 		case SIOCGLIFINDEX :
 		case SIOCGLIFFLAGS :
 		case SIOCGLIFMTU :
+		case SIOCGLIFHWADDR :
 			error = ddi_copyout(&lifreq, (void *)arg,
 			    sizeof (lifreq), 0);
 			break;
@@ -1128,16 +1215,16 @@
 		bcopy(optval, &mreq, sizeof (mreq));
 		if (ps->ps_linkid != mreq.mr_ifindex)
 			return (EINVAL);
-
-		if (mreq.mr_alen !=
-		    ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen)
-			return (EINVAL);
 	}
 
 	switch (option_name) {
 	case PACKET_ADD_MEMBERSHIP :
 		switch (mreq.mr_type) {
 		case PACKET_MR_MULTICAST :
+			if (mreq.mr_alen !=
+			    ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen)
+				return (EINVAL);
+
 			error = mac_multicast_add(ps->ps_mch, mreq.mr_address);
 			break;
 
@@ -1154,6 +1241,10 @@
 	case PACKET_DROP_MEMBERSHIP :
 		switch (mreq.mr_type) {
 		case PACKET_MR_MULTICAST :
+			if (mreq.mr_alen !=
+			    ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen)
+				return (EINVAL);
+
 			mac_multicast_remove(ps->ps_mch, mreq.mr_address);
 			break;
 
@@ -1393,11 +1484,19 @@
 
 /*
  * This table maps the MAC types in Solaris to the ARPHRD_* values used
- * on Linux. This is used with the SIOCGIFHWADDR ioctl.
+ * on Linux. This is used with the SIOCGIFHWADDR/SIOCGLIFHWADDR ioctl.
+ *
+ * The symbols in this table are *not* pulled in from <net/if_arp.h>,
+ * they are pulled from <netpacket/packet.h>, thus it acts as a source
+ * of supplementary information to the ARP table.
  */
 static uint_t arphrd_to_dl[][2] = {
-	{ ARPHRD_ETHER,		DL_ETHER },
 	{ ARPHRD_IEEE80211,	DL_WIFI },
+	{ ARPHRD_TUNNEL,	DL_IPV4 },
+	{ ARPHRD_TUNNEL,	DL_IPV6 },
+	{ ARPHRD_TUNNEL,	DL_6TO4 },
+	{ ARPHRD_AX25,		DL_X25 },
+	{ ARPHRD_ATM,		DL_ATM },
 	{ 0,			0 }
 };
 
@@ -1409,5 +1508,5 @@
 	for (i = 0; arphrd_to_dl[i][0] != 0; i++)
 		if (arphrd_to_dl[i][1] == dltype)
 			return (arphrd_to_dl[i][0]);
-	return (0);
+	return (arp_hw_type(dltype));
 }
--- a/usr/src/uts/common/net/if_arp.h	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/net/if_arp.h	Thu Aug 12 16:05:23 2010 -0700
@@ -1,6 +1,5 @@
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -12,7 +11,6 @@
 #ifndef	_NET_IF_ARP_H
 #define	_NET_IF_ARP_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 /* if_arp.h 1.5 88/08/19 SMI; from UCB 7.1 1/24/86	*/
 
 #include <sys/types.h>
@@ -35,12 +33,17 @@
 struct	arphdr {
 	ushort_t ar_hrd;	/* format of hardware address */
 #define	ARPHRD_ETHER 	1	/* ethernet hardware address */
+#define	ARPHRD_EETHER	2	/* experimental ethernet */
+#define	ARPHRD_AX25	3	/* amateur readio ax.25 */
+#define	ARPHRD_CHAOS	5	/* Chaos net */
 #define	ARPHRD_IEEE802 	6	/* IEEE 802 hardware address */
+#define	ARPHRD_ARCNET	7	/* ARCNET */
 #define	ARPHRD_FRAME	15	/* Frame relay */
 #define	ARPHRD_ATM	16	/* ATM */
 #define	ARPHRD_HDLC	17	/* HDLC */
 #define	ARPHRD_FC	18	/* Fibre Channel RFC 4338 */
 #define	ARPHRD_IPATM	19	/* ATM RFC 2225 */
+#define	ARPHRD_METRICOM	23	/* Metricom */
 #define	ARPHRD_TUNNEL	31	/* IPsec Tunnel RFC 3456 */
 #define	ARPHRD_IB	32	/* IPoIB hardware address */
 	ushort_t ar_pro;	/* format of protocol address */
--- a/usr/src/uts/common/sys/sockio.h	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/common/sys/sockio.h	Thu Aug 12 16:05:23 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -310,7 +309,12 @@
 
 #define	SIOCSQPTR	_IOWR('i', 184, int)    /* set q_ptr of stream */
 
-#define	SIOCGIFHWADDR	_IOWR('i', 185, int)	/* PF_PACKET */
+/*
+ * SIOCGIFHWADDR and SIOCGLIFHWADDR (below) are available for PF_PACKET,
+ * PF_INET and PF_INET6 sockets.
+ */
+#define	SIOCGIFHWADDR	_IOWR('i', 185, struct ifreq)
+
 #define	SIOCGSTAMP	_IOWR('i', 186, struct timeval)	/* PF_PACKET */
 
 /*
@@ -337,6 +341,8 @@
  */
 #define	SIOCSLIFPREFIX		_IOWR('i', 191, struct lifreq)
 
+#define	SIOCGLIFHWADDR	_IOWR('i', 192, struct lifreq)
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/intel/sockpfp/Makefile	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/intel/sockpfp/Makefile	Thu Aug 12 16:05:23 2010 -0700
@@ -58,7 +58,7 @@
 #
 CFLAGS += $(CCVERBOSE)
 
-LDFLAGS += -dy -Nfs/sockfs -Nmisc/dls -Nmisc/mac -Ndrv/bpf
+LDFLAGS += -dy -Nfs/sockfs -Nmisc/dls -Nmisc/mac -Ndrv/bpf -Nsrc/ip
 INC_PATH += -I$(UTSBASE)/common/inet/sockmods -I$(UTSBASE)/common/io/bpf
 
 #
--- a/usr/src/uts/sparc/sockpfp/Makefile	Thu Aug 12 15:59:36 2010 -0600
+++ b/usr/src/uts/sparc/sockpfp/Makefile	Thu Aug 12 16:05:23 2010 -0700
@@ -58,7 +58,7 @@
 #
 CFLAGS += $(CCVERBOSE)
 
-LDFLAGS += -dy -Nfs/sockfs -Nmisc/dls -Nmisc/mac -Ndrv/bpf
+LDFLAGS += -dy -Nfs/sockfs -Nmisc/dls -Nmisc/mac -Ndrv/bpf -Ndrv/ip
 INC_PATH += -I$(UTSBASE)/common/inet/sockmods -I$(UTSBASE)/common/io/bpf
 
 #