diff options
| -rw-r--r-- | sys/net/if.c | 55 | ||||
| -rw-r--r-- | sys/net/if_var.h | 1 | ||||
| -rw-r--r-- | sys/sys/sockio.h | 1 |
3 files changed, 57 insertions, 0 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 982592df8463..829ede27b94d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -52,7 +52,9 @@ #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_arp.h> #include <net/if_dl.h> +#include <net/if_types.h> #include <net/radix.h> #include <net/route.h> @@ -910,6 +912,13 @@ ifioctl(so, cmd, data, p) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, cmd, data)); + case SIOCSIFLLADDR: + error = suser(p); + if (error) + return (error); + return if_setlladdr(ifp, + ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); + default: oif_flags = ifp->if_flags; if (so->so_proto == 0) @@ -1309,6 +1318,52 @@ if_delmulti(ifp, sa) return 0; } +/* + * Set the link layer address on an interface. + * + * At this time we only support certain types of interfaces, + * and we don't allow the length of the address to change. + */ +int +if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) +{ + struct sockaddr_dl *sdl; + struct ifaddr *ifa; + + ifa = ifnet_addrs[ifp->if_index - 1]; + if (ifa == NULL) + return (EINVAL); + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + if (sdl == NULL) + return (EINVAL); + if (len != sdl->sdl_alen) /* don't allow length to change */ + return (EINVAL); + switch (ifp->if_type) { + case IFT_ETHER: /* these types use struct arpcom */ + case IFT_FDDI: + case IFT_XETHER: + case IFT_ISO88025: + case IFT_PROPVIRTUAL: /* XXX waiting for IFT_8021_VLAN */ + bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len); + bcopy(lladdr, LLADDR(sdl), len); + break; + default: + return (ENODEV); + } + /* + * 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) != 0) { + ifp->if_flags &= ~IFF_UP; + (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); + ifp->if_flags |= IFF_UP; + (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); + } + return (0); +} + struct ifmultiaddr * ifmaof_ifpforaddr(sa, ifp) struct sockaddr *sa; diff --git a/sys/net/if_var.h b/sys/net/if_var.h index e6f07853622e..d16fc00c4313 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -340,6 +340,7 @@ int if_delmulti __P((struct ifnet *, struct sockaddr *)); void if_detach __P((struct ifnet *)); void if_down __P((struct ifnet *)); void if_route __P((struct ifnet *, int flag, int fam)); +int if_setlladdr __P((struct ifnet *, const u_char *, int)); void if_unroute __P((struct ifnet *, int flag, int fam)); void if_up __P((struct ifnet *)); /*void ifinit __P((void));*/ /* declared in systm.h for main() */ diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 7aee3dffcaa6..c107562eaec3 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -96,5 +96,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_ */ |
