Subject: kern/30665: ifconfig lladdr support for SIOCSIFLLADDR ioctl to change link address
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <richy@fatkid.org>
List: netbsd-bugs
Date: 07/05/2005 06:04:00
>Number: 30665
>Category: kern
>Synopsis: ifconfig lladdr support for SIOCSIFLLADDR ioctl to change link address
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Tue Jul 05 06:04:00 +0000 2005
>Originator: Richy Kim
>Release: NetBSD-current July 4, 2005
>Organization:
>Environment:
NetBSD chunk 3.99.7 NetBSD 3.99.7 (GENERIC.MP) #3: Mon Jul 4 16:19:19 PDT 2005 richy@chunk:/home/richy/sandbox/netbsd/obj/sys/arch/i386/compile/GENERIC.MP i386
>Description:
Based off of existing patches for FreeBSD and OpenBSD, attached below are the diffs to support SIOCSFLLADDR ioctl functionality into the kernel and the corresponding ifconfig lladdr command to change the ethernet (mac,link) address for a given interface.
-r.
>How-To-Repeat:
N/A
>Fix:
http://fatkid.org/netbsd/netbsd.lladdr.diff
http://fatkid.org/netbsd/netbsd.ifconfig.diff
Patch against -current (as of July 4, 2005)
Index: sys/sys/sockio.h
===================================================================
RCS file: /cvsroot/src/sys/sys/sockio.h,v
retrieving revision 1.22
diff -u -r1.22 sockio.h
--- sys/sys/sockio.h 26 Feb 2005 22:25:34 -0000 1.22
+++ sys/sys/sockio.h 5 Jul 2005 05:51:58 -0000
@@ -81,6 +81,7 @@
#define SIOCALIFADDR _IOW('i', 28, struct if_laddrreq) /* add IF addr */
#define SIOCGLIFADDR _IOWR('i', 29, struct if_laddrreq) /* get IF addr */
#define SIOCDLIFADDR _IOW('i', 30, struct if_laddrreq) /* delete IF addr */
+#define SIOCSIFLLADDR _IOW('i', 31, struct ifreq) /* set link level addr */
#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */
#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.159
diff -u -r1.159 if.c
--- sys/net/if.c 22 Jun 2005 06:16:02 -0000 1.159
+++ sys/net/if.c 5 Jul 2005 05:52:06 -0000
@@ -1580,6 +1580,48 @@
error = (*ifp->if_ioctl)(ifp, cmd, data);
break;
+ case SIOCSIFLLADDR:
+ {
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return (error);
+ struct ifaddr *ifa = ifnet_addrs[ifp->if_index];
+ if (ifa == NULL)
+ return (EINVAL);
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ if (sdl == NULL)
+ return (EINVAL);
+ if (ifr->ifr_addr.sa_len != ETHER_ADDR_LEN)
+ return (EINVAL);
+ if (ETHER_IS_MULTICAST(ifr->ifr_addr.sa_data))
+ return (EINVAL);
+ switch (ifp->if_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_XETHER:
+ case IFT_ISO88025:
+ case IFT_L2VLAN:
+ case IFT_ARCNET:
+ bcopy((caddr_t)ifr->ifr_addr.sa_data, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ return (ENODEV);
+ }
+ if (ifp->if_flags & IFF_UP) {
+ int x = splnet();
+ ifp->if_flags &= ~IFF_UP;
+ (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
+ ifp->if_flags |= IFF_UP;
+ (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
+ splx(x);
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+ if (ifa->ifa_addr != NULL &&
+ ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(ifp, ifa);
+ }
+ }
+ break;
+ }
+
case SIOCSDRVSPEC:
case SIOCS80211NWID:
case SIOCS80211NWKEY:
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.78
diff -u -r1.78 ifconfig.8
--- sbin/ifconfig/ifconfig.8 2 May 2005 15:37:06 -0000 1.78
+++ sbin/ifconfig/ifconfig.8 5 Jul 2005 05:55:57 -0000
@@ -238,6 +238,16 @@
and 802.11g
.Pq Dq 11g
operating modes.
+.It Cm lladdr Ar addr
+Set the link-level address on an interface. This can be used to
+e.g. set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific. The address
+.Ar addr
+is specified as a series of colon-separated hex digits. If the
+interface is already up when this option is used, it will be
+briefly brought down and then brought back up again in order to
+ensure that the receive filter in the underlying ethernet
+hardware is properly reprogrammed.
.It Cm instance Ar minst
Set the media instance to
.Ar minst .
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.168
diff -u -r1.168 ifconfig.c
--- sbin/ifconfig/ifconfig.c 2 May 2005 15:35:16 -0000 1.168
+++ sbin/ifconfig/ifconfig.c 5 Jul 2005 05:56:05 -0000
@@ -146,6 +146,7 @@
void notealias(const char *, int);
void notrailers(const char *, int);
void setifaddr(const char *, int);
+void setiflladdr(const char *, int);
void setifdstaddr(const char *, int);
void setifflags(const char *, int);
void setifcaps(const char *, int);
@@ -267,6 +268,7 @@
{ "mode", NEXTARG, A_MEDIAMODE, setmediamode },
{ "instance", NEXTARG, A_MEDIAINST, setmediainst },
{ "inst", NEXTARG, A_MEDIAINST, setmediainst },
+ { "lladdr", NEXTARG, 0, setiflladdr},
{ "ip4csum-tx", IFCAP_CSUM_IPv4_Tx,0, setifcaps },
{ "-ip4csum-tx",-IFCAP_CSUM_IPv4_Tx,0, setifcaps },
{ "ip4csum-rx", IFCAP_CSUM_IPv4_Rx,0, setifcaps },
@@ -840,6 +842,25 @@
}
void
+setiflladdr(const char *addr, int param)
+{
+ struct ether_addr *eap;
+
+ eap = ether_aton(addr);
+ if (eap == NULL) {
+ warn("malformed link-level address");
+ return;
+ }
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
+ ifr.ifr_addr.sa_family = AF_LINK;
+ bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
+ if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
+ warn("ioctl (set lladdr)");
+ return;
+}
+
+void
setifnetmask(const char *addr, int d)
{
(*afp->af_getaddr)(addr, MASK);
@@ -1488,7 +1509,7 @@
"interface\n"
"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
"\t\t[ alias | -alias ] ]\n"
- "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
+ "\t[ up ] [ down ] [ metric n ] [ mtu n ] [ lladdr addr ]\n"
"\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
"\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
"\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"