summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_freebsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211/ieee80211_freebsd.c')
-rw-r--r--sys/net80211/ieee80211_freebsd.c90
1 files changed, 76 insertions, 14 deletions
diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c
index 9a8e941..3af75df 100644
--- a/sys/net80211/ieee80211_freebsd.c
+++ b/sys/net80211/ieee80211_freebsd.c
@@ -69,27 +69,58 @@ static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state");
static const char wlanname[] = "wlan";
static struct if_clone *wlan_cloner;
+/*
+ * Allocate/free com structure in conjunction with ifnet;
+ * these routines are registered with if_register_com_alloc
+ * below and are called automatically by the ifnet code
+ * when the ifnet of the parent device is created.
+ */
+static void *
+wlan_alloc(u_char type, struct ifnet *ifp)
+{
+ struct ieee80211com *ic;
+
+ ic = IEEE80211_MALLOC(sizeof(struct ieee80211com), M_80211_COM,
+ IEEE80211_M_WAITOK | IEEE80211_M_ZERO);
+ ic->ic_ifp = ifp;
+
+ return (ic);
+}
+
+static void
+wlan_free(void *ic, u_char type)
+{
+ IEEE80211_FREE(ic, M_80211_COM);
+}
+
static int
wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
{
struct ieee80211_clone_params cp;
struct ieee80211vap *vap;
struct ieee80211com *ic;
+ struct ifnet *ifp;
int error;
error = copyin(params, &cp, sizeof(cp));
if (error)
return error;
- ic = ieee80211_find_com(cp.icp_parent);
- if (ic == NULL)
+ ifp = ifunit(cp.icp_parent);
+ if (ifp == NULL)
return ENXIO;
+ /* XXX move printfs to DIAGNOSTIC before release */
+ if (ifp->if_type != IFT_IEEE80211) {
+ if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__);
+ return ENXIO;
+ }
if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
- ic_printf(ic, "%s: invalid opmode %d\n", __func__,
- cp.icp_opmode);
+ if_printf(ifp, "%s: invalid opmode %d\n",
+ __func__, cp.icp_opmode);
return EINVAL;
}
+ ic = ifp->if_l2com;
if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
- ic_printf(ic, "%s mode not supported\n",
+ if_printf(ifp, "%s mode not supported\n",
ieee80211_opmode_name[cp.icp_opmode]);
return EOPNOTSUPP;
}
@@ -100,13 +131,13 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
(1)
#endif
) {
- ic_printf(ic, "TDMA not supported\n");
+ if_printf(ifp, "TDMA not supported\n");
return EOPNOTSUPP;
}
vap = ic->ic_vap_create(ic, wlanname, unit,
cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
cp.icp_flags & IEEE80211_CLONE_MACADDR ?
- cp.icp_macaddr : ic->ic_macaddr);
+ cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp));
return (vap == NULL ? EIO : 0);
}
@@ -497,19 +528,17 @@ ieee80211_process_callback(struct ieee80211_node *ni,
* (the callers will first need modifying.)
*/
int
-ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
+ieee80211_parent_xmitpkt(struct ieee80211com *ic,
+ struct mbuf *m)
{
- int error;
-
+ struct ifnet *parent = ic->ic_ifp;
/*
* Assert the IC TX lock is held - this enforces the
* processing -> queuing order is maintained
*/
IEEE80211_TX_LOCK_ASSERT(ic);
- error = ic->ic_transmit(ic, m);
- if (error)
- m_freem(m);
- return (error);
+
+ return (parent->if_transmit(parent, m));
}
/*
@@ -807,6 +836,7 @@ ieee80211_load_module(const char *modname)
}
static eventhandler_tag wlan_bpfevent;
+static eventhandler_tag wlan_ifllevent;
static void
bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
@@ -834,6 +864,33 @@ bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
}
}
+static void
+wlan_iflladdr(void *arg __unused, struct ifnet *ifp)
+{
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211vap *vap, *next;
+
+ if (ifp->if_type != IFT_IEEE80211 || ic == NULL)
+ return;
+
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH_SAFE(vap, &ic->ic_vaps, iv_next, next) {
+ /*
+ * If the MAC address has changed on the parent and it was
+ * copied to the vap on creation then re-sync.
+ */
+ if (vap->iv_ic == ic &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_UNIQMAC) == 0) {
+ IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
+ IEEE80211_UNLOCK(ic);
+ if_setlladdr(vap->iv_ifp, IF_LLADDR(ifp),
+ IEEE80211_ADDR_LEN);
+ IEEE80211_LOCK(ic);
+ }
+ }
+ IEEE80211_UNLOCK(ic);
+}
+
/*
* Module glue.
*
@@ -848,12 +905,17 @@ wlan_modevent(module_t mod, int type, void *unused)
printf("wlan: <802.11 Link Layer>\n");
wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
bpf_track, 0, EVENTHANDLER_PRI_ANY);
+ wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
+ wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
wlan_cloner = if_clone_simple(wlanname, wlan_clone_create,
wlan_clone_destroy, 0);
+ if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
return 0;
case MOD_UNLOAD:
+ if_deregister_com_alloc(IFT_IEEE80211);
if_clone_detach(wlan_cloner);
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
+ EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
return 0;
}
return EINVAL;
OpenPOWER on IntegriCloud