summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarchie <archie@FreeBSD.org>2000-08-15 00:48:38 +0000
committerarchie <archie@FreeBSD.org>2000-08-15 00:48:38 +0000
commit63e7d24009d010dea2cd23b7a1b4d2ebd2a1aadd (patch)
tree9ad48c309ff073c4fe8b80fdbe91068a8634ef2a
parent5d654e2338d33c452f651e3a018b7725e93edc16 (diff)
downloadFreeBSD-src-63e7d24009d010dea2cd23b7a1b4d2ebd2a1aadd.zip
FreeBSD-src-63e7d24009d010dea2cd23b7a1b4d2ebd2a1aadd.tar.gz
Export the functionality of SIOCSIFLLADDR with if_setlladdr()
and add some more rigorous sanity checking in the process. Reviewed by: freebsd-net
-rw-r--r--sys/net/if.c75
-rw-r--r--sys/net/if_var.h1
2 files changed, 51 insertions, 25 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index d7feb3c..829ede2 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -54,6 +54,7 @@
#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>
@@ -762,8 +763,6 @@ 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;
@@ -917,29 +916,9 @@ ifioctl(so, cmd, data, p)
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);
+ 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)
@@ -1339,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 e6f0785..d16fc00 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() */
OpenPOWER on IntegriCloud