Implement SIOCSIFLLADDR, which allows you to change the link-level

address on an interface. This basically allows you to do what my
little setmac module/utility does via ifconfig. This involves the
following changes:

socket.h: define SIOCSIFLLADDR
if.c: add support for SIOCSIFLLADDR, which resets the values in
      the arpcom struct and sockaddr_dl for the specified interface.
      Note that if the interface is already up, we need to down/up
      it in order to program the underlying hardware's receive filter.
ifconfig.c: add lladdr command
ifconfig.8: document lladdr command

You can now force the MAC address on any ethernet interface to be
whatever you want. (The change is not sticky across reboots of course:
we don't actually reprogram the EEPROM or anything.) Actually, you
can reprogram the MAC address on other kinds of interfaces too; this
shouldn't be ethernet-specific (though at the moment it's limited to
6 bytes of address data).

Nobody ran up to me and said "this is the politically correct way to
do this!" so I don't want to hear any complaints from people who think
I could have done it more elegantly. Consider yourselves lucky I didn't
do it by having ifconfig tread all over /dev/kmem.
This commit is contained in:
Bill Paul 2000-06-16 20:14:43 +00:00
parent 8f76bcf052
commit b106252c19
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61734
4 changed files with 67 additions and 1 deletions

View File

@ -189,6 +189,16 @@ This action does not automatically disable routes using the interface.
.\" IP encapsulation of
.\" .Tn CLNP
.\" packets is done differently.
.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 insure that the receive
filter in the underlying ethernet hardware is properly reprogrammed.
.It Cm media Ar type
If the driver supports the media selection system, set the media type
of the interface to

View File

@ -53,6 +53,7 @@ static const char rcsid[] =
#include <sys/module.h>
#include <sys/linker.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
@ -153,7 +154,7 @@ c_func setifprefixlen;
c_func setip6flags;
#endif
c_func setifipdst;
c_func setifflags, setifmetric, setifmtu;
c_func setifflags, setifmetric, setifmtu, setiflladdr;
#define NEXTARG 0xffffff
@ -212,6 +213,7 @@ struct cmd {
{ "compress", IFF_LINK0, setifflags },
{ "noicmp", IFF_LINK1, setifflags },
{ "mtu", NEXTARG, setifmtu },
{ "lladdr", NEXTARG, setiflladdr },
{ 0, 0, setifaddr },
{ 0, 0, setifdstaddr },
};
@ -815,6 +817,29 @@ setifmtu(val, dummy, s, afp)
warn("ioctl (set mtu)");
}
void
setiflladdr(val, dummy, s, afp)
const char *val;
int dummy __unused;
int s;
const struct afswtch *afp;
{
struct ether_addr *ea;
ea = ether_aton(val);
if (ea == 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(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
warn("ioctl (set lladdr)");
return;
}
#define IFFBITS \
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \

View File

@ -52,6 +52,7 @@
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/radix.h>
#include <net/route.h>
@ -763,6 +764,8 @@ ifioctl(so, cmd, data, p)
{
register struct ifnet *ifp;
register struct ifreq *ifr;
register struct ifaddr *ifa;
struct sockaddr_dl *sdl;
struct ifstat *ifs;
int error;
short oif_flags;
@ -912,6 +915,33 @@ ifioctl(so, cmd, data, p)
return (EOPNOTSUPP);
return ((*ifp->if_ioctl)(ifp, cmd, data));
case SIOCSIFLLADDR:
error = suser(p);
if (error)
return (error);
ifa = ifnet_addrs[ifp->if_index - 1];
if (ifa == NULL)
return(EINVAL);
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl == NULL)
return(EINVAL);
bcopy(ifr->ifr_addr.sa_data,
((struct arpcom *)ifp->if_softc)->ac_enaddr,
ifr->ifr_addr.sa_len);
bcopy(ifr->ifr_addr.sa_data, LLADDR(sdl),
ifr->ifr_addr.sa_len);
/*
* If the interface is already up, we need
* to re-init it in order to reprogram its
* address filter.
*/
if (ifp->if_flags & IFF_UP) {
ifp->if_flags &= ~IFF_UP;
(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);
ifp->if_flags |= IFF_UP;
(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);
}
return(0);
default:
oif_flags = ifp->if_flags;
if (so->so_proto == 0)

View File

@ -94,5 +94,6 @@
#define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */
#define SIOCGIFSTATUS _IOWR('i', 59, struct ifstat) /* get IF status */
#define SIOCSIFLLADDR _IOW('i', 60, struct ifreq) /* set link level addr */
#endif /* !_SYS_SOCKIO_H_ */