From owner-freebsd-net@freebsd.org Tue Sep 8 15:22:44 2015 Return-Path: Delivered-To: freebsd-net@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 23E8D9CC3E3 for ; Tue, 8 Sep 2015 15:22:44 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from mailman.ysv.freebsd.org (mailman.ysv.freebsd.org [IPv6:2001:1900:2254:206a::50:5]) by mx1.freebsd.org (Postfix) with ESMTP id 093C01873 for ; Tue, 8 Sep 2015 15:22:44 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: by mailman.ysv.freebsd.org (Postfix) id 082649CC3E2; Tue, 8 Sep 2015 15:22:44 +0000 (UTC) Delivered-To: net@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0791D9CC3E1 for ; Tue, 8 Sep 2015 15:22:44 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from cell.glebius.int.ru (glebius.int.ru [81.19.69.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "cell.glebius.int.ru", Issuer "cell.glebius.int.ru" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 508F91872; Tue, 8 Sep 2015 15:22:42 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from cell.glebius.int.ru (localhost [127.0.0.1]) by cell.glebius.int.ru (8.15.2/8.15.2) with ESMTPS id t88FMXIs051335 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 8 Sep 2015 18:22:33 +0300 (MSK) (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by cell.glebius.int.ru (8.15.2/8.15.2/Submit) id t88FMXV3051334; Tue, 8 Sep 2015 18:22:33 +0300 (MSK) (envelope-from glebius@FreeBSD.org) X-Authentication-Warning: cell.glebius.int.ru: glebius set sender to glebius@FreeBSD.org using -f Date: Tue, 8 Sep 2015 18:22:33 +0300 From: Gleb Smirnoff To: Adrian Chadd , Andriy Voskoboinyk Cc: "net@freebsd.org" Subject: more net80211 changes :/ Message-ID: <20150908152233.GV1023@glebius.int.ru> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="mxv5cy4qt+RJ9ypb" Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 08 Sep 2015 15:22:44 -0000 --mxv5cy4qt+RJ9ypb Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi! It looks like another sweep over net80211 drivers is required. It isn't going to be as huge as previous one. The problem is that in the "new world order", there will be only if_attach(), instead of if_alloc() / fill & hack / ether_ifattach. What right now happens with net80211 is that all drivers have the same copy & paste in their ic_vap_create, which yields in a sequence of: - if_alloc - driver specific code - ether_ifattach Which isn't possible to collapse into if_attach(), since driver code is in the middle. Another problem is embedding if ieee80211_vap into driver's softc. This is a bad habit, which was proved by ifnet experience (fixed decade ago). What patch does: - Inline ieee80211_vap_setup() and ieee80211_vap_attach() into wlan_clone_create(). Note, that this moves code from ieee80211.c to into ieee80211_freebsd.c, which is good, since this code about interaction with ifnet layer, which is FreeBSD specific and will be more FreeBSD specific. As dependency ifmedia support code and ieee80211_get_counter() also naturally move to the same file. - In the new long wlan_clone_create(), after initial error checking call ic_vap_preattach() to allow driver do its own error checking. I predict that for now ath(4) will be the only driver to use ic_vap_preattach(). - If no errors, go with allocating and attaching the interface, and then call ic_vap_postattach. - The ic_vap_postattach() for all drivers (save ath) would be remnants of ic_vap_create(), where all copy and paste is removed and only driver specific bits remain. - ic_vap_postattach() may allocate driver specific softc for vap, which now longer has ieee80211_vap embedded. This also removes all ambiguities with mac address handling, which was juggled between three functions before. The current patch covers iwn(4) only. Now sending this mail with patched driver. Changing MAC aldo tested - works. I'm starting to convert rest of drivers and meanwhile, waiting for your input. May be you have ideas what else can be improved here. -- Totus tuus, Glebius. --mxv5cy4qt+RJ9ypb Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="new_vap_attach.diff" Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c (revision 287554) +++ sys/dev/iwn/if_iwn.c (working copy) @@ -136,10 +136,7 @@ static int iwn5000_attach(struct iwn_softc *, uint static int iwn_config_specific(struct iwn_softc *, uint16_t); static void iwn_radiotap_attach(struct iwn_softc *); static void iwn_sysctlattach(struct iwn_softc *); -static struct ieee80211vap *iwn_vap_create(struct ieee80211com *, - const char [IFNAMSIZ], int, enum ieee80211_opmode, int, - const uint8_t [IEEE80211_ADDR_LEN], - const uint8_t [IEEE80211_ADDR_LEN]); +static void iwn_vap_postattach(struct ieee80211com *, struct ieee80211vap *); static void iwn_vap_delete(struct ieee80211vap *); static int iwn_detach(device_t); static int iwn_shutdown(device_t); @@ -640,7 +637,7 @@ iwn_attach(device_t dev) } ieee80211_ifattach(ic); - ic->ic_vap_create = iwn_vap_create; + ic->ic_vap_postattach = iwn_vap_postattach; ic->ic_ioctl = iwn_ioctl; ic->ic_parent = iwn_parent; ic->ic_vap_delete = iwn_vap_delete; @@ -666,6 +663,7 @@ iwn_attach(device_t dev) ic->ic_scan_curchan = iwn_scan_curchan; ic->ic_scan_mindwell = iwn_scan_mindwell; ic->ic_setregdomain = iwn_setregdomain; + ic->ic_media_change = iwn_media_change; iwn_radiotap_attach(sc); @@ -1317,22 +1315,13 @@ iwn_sysctlattach(struct iwn_softc *sc) #endif } -static struct ieee80211vap * -iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, - enum ieee80211_opmode opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t mac[IEEE80211_ADDR_LEN]) +static void +iwn_vap_postattach(struct ieee80211com *ic, struct ieee80211vap *vap) { struct iwn_softc *sc = ic->ic_softc; struct iwn_vap *ivp; - struct ieee80211vap *vap; - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ - return NULL; - - ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); - vap = &ivp->iv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK); ivp->ctx = IWN_RXON_BSS_CTX; vap->iv_bmissthreshold = 10; /* override default */ /* Override with driver methods. */ @@ -1339,19 +1328,14 @@ iwn_sysctlattach(struct iwn_softc *sc) ivp->iv_newstate = vap->iv_newstate; vap->iv_newstate = iwn_newstate; sc->ivap[IWN_RXON_BSS_CTX] = vap; - + vap->iv_softc = ivp; ieee80211_ratectl_init(vap); - /* Complete setup. */ - ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status, - mac); - ic->ic_opmode = opmode; - return vap; } static void iwn_vap_delete(struct ieee80211vap *vap) { - struct iwn_vap *ivp = IWN_VAP(vap); + struct iwn_vap *ivp = vap->iv_softc; ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); @@ -2814,7 +2798,7 @@ iwn_media_change(struct ifnet *ifp) static int iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct iwn_vap *ivp = IWN_VAP(vap); + struct iwn_vap *ivp = vap->iv_softc; struct ieee80211com *ic = vap->iv_ic; struct iwn_softc *sc = ic->ic_softc; int error = 0; Index: sys/dev/iwn/if_iwnvar.h =================================================================== --- sys/dev/iwn/if_iwnvar.h (revision 287554) +++ sys/dev/iwn/if_iwnvar.h (working copy) @@ -221,16 +221,11 @@ struct iwn_ops { }; struct iwn_vap { - struct ieee80211vap iv_vap; - uint8_t iv_ridx; - int (*iv_newstate)(struct ieee80211vap *, enum ieee80211_state, int); int ctx; - int beacon_int; }; -#define IWN_VAP(_vap) ((struct iwn_vap *)(_vap)) struct iwn_softc { device_t sc_dev; Index: sys/net80211/ieee80211.c =================================================================== --- sys/net80211/ieee80211.c (revision 287554) +++ sys/net80211/ieee80211.c (working copy) @@ -86,15 +86,8 @@ const int ieee80211_opcap[IEEE80211_OPMODE_MAX] = const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag); -static void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag); -static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag); -static int ieee80211_media_setup(struct ieee80211com *ic, - struct ifmedia *media, int caps, int addsta, - ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); static int media_status(enum ieee80211_opmode, const struct ieee80211_channel *); -static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter); MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); @@ -400,224 +393,6 @@ ieee80211_find_com(const char *name) return (ic); } -/* - * Default reset method for use with the ioctl support. This - * method is invoked after any state change in the 802.11 - * layer that should be propagated to the hardware but not - * require re-initialization of the 802.11 state machine (e.g - * rescanning for an ap). We always return ENETRESET which - * should cause the driver to re-initialize the device. Drivers - * can override this method to implement more optimized support. - */ -static int -default_reset(struct ieee80211vap *vap, u_long cmd) -{ - return ENETRESET; -} - -/* - * Add underlying device errors to vap errors. - */ -static uint64_t -ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt) -{ - struct ieee80211vap *vap = ifp->if_softc; - struct ieee80211com *ic = vap->iv_ic; - uint64_t rv; - - rv = if_get_counter_default(ifp, cnt); - switch (cnt) { - case IFCOUNTER_OERRORS: - rv += counter_u64_fetch(ic->ic_oerrors); - break; - case IFCOUNTER_IERRORS: - rv += counter_u64_fetch(ic->ic_ierrors); - break; - default: - break; - } - - return (rv); -} - -/* - * Prepare a vap for use. Drivers use this call to - * setup net80211 state in new vap's prior attaching - * them with ieee80211_vap_attach (below). - */ -int -ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, - const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, - int flags, const uint8_t bssid[IEEE80211_ADDR_LEN]) -{ - struct ifnet *ifp; - - ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - ic_printf(ic, "%s: unable to allocate ifnet\n", - __func__); - return ENOMEM; - } - if_initname(ifp, name, unit); - ifp->if_softc = vap; /* back pointer */ - ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; - ifp->if_transmit = ieee80211_vap_transmit; - ifp->if_qflush = ieee80211_vap_qflush; - ifp->if_ioctl = ieee80211_ioctl; - ifp->if_init = ieee80211_init; - ifp->if_get_counter = ieee80211_get_counter; - - vap->iv_ifp = ifp; - vap->iv_ic = ic; - vap->iv_flags = ic->ic_flags; /* propagate common flags */ - vap->iv_flags_ext = ic->ic_flags_ext; - vap->iv_flags_ven = ic->ic_flags_ven; - vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; - vap->iv_htcaps = ic->ic_htcaps; - vap->iv_htextcaps = ic->ic_htextcaps; - vap->iv_opmode = opmode; - vap->iv_caps |= ieee80211_opcap[opmode]; - vap->iv_myaddr = ic->ic_macaddr; - switch (opmode) { - case IEEE80211_M_WDS: - /* - * WDS links must specify the bssid of the far end. - * For legacy operation this is a static relationship. - * For non-legacy operation the station must associate - * and be authorized to pass traffic. Plumbing the - * vap to the proper node happens when the vap - * transitions to RUN state. - */ - IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid); - vap->iv_flags |= IEEE80211_F_DESBSSID; - if (flags & IEEE80211_CLONE_WDSLEGACY) - vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY; - break; -#ifdef IEEE80211_SUPPORT_TDMA - case IEEE80211_M_AHDEMO: - if (flags & IEEE80211_CLONE_TDMA) { - /* NB: checked before clone operation allowed */ - KASSERT(ic->ic_caps & IEEE80211_C_TDMA, - ("not TDMA capable, ic_caps 0x%x", ic->ic_caps)); - /* - * Propagate TDMA capability to mark vap; this - * cannot be removed and is used to distinguish - * regular ahdemo operation from ahdemo+tdma. - */ - vap->iv_caps |= IEEE80211_C_TDMA; - } - break; -#endif - default: - break; - } - /* auto-enable s/w beacon miss support */ - if (flags & IEEE80211_CLONE_NOBEACONS) - vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS; - /* auto-generated or user supplied MAC address */ - if (flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR)) - vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC; - /* - * Enable various functionality by default if we're - * capable; the driver can override us if it knows better. - */ - if (vap->iv_caps & IEEE80211_C_WME) - vap->iv_flags |= IEEE80211_F_WME; - if (vap->iv_caps & IEEE80211_C_BURST) - vap->iv_flags |= IEEE80211_F_BURST; - /* NB: bg scanning only makes sense for station mode right now */ - if (vap->iv_opmode == IEEE80211_M_STA && - (vap->iv_caps & IEEE80211_C_BGSCAN)) - vap->iv_flags |= IEEE80211_F_BGSCAN; - vap->iv_flags |= IEEE80211_F_DOTH; /* XXX no cap, just ena */ - /* NB: DFS support only makes sense for ap mode right now */ - if (vap->iv_opmode == IEEE80211_M_HOSTAP && - (vap->iv_caps & IEEE80211_C_DFS)) - vap->iv_flags_ext |= IEEE80211_FEXT_DFS; - - vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ - vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; - vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; - /* - * Install a default reset method for the ioctl support; - * the driver can override this. - */ - vap->iv_reset = default_reset; - - ieee80211_sysctl_vattach(vap); - ieee80211_crypto_vattach(vap); - ieee80211_node_vattach(vap); - ieee80211_power_vattach(vap); - ieee80211_proto_vattach(vap); -#ifdef IEEE80211_SUPPORT_SUPERG - ieee80211_superg_vattach(vap); -#endif - ieee80211_ht_vattach(vap); - ieee80211_scan_vattach(vap); - ieee80211_regdomain_vattach(vap); - ieee80211_radiotap_vattach(vap); - ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE); - - return 0; -} - -/* - * Activate a vap. State should have been prepared with a - * call to ieee80211_vap_setup and by the driver. On return - * from this call the vap is ready for use. - */ -int -ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, - ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN]) -{ - struct ifnet *ifp = vap->iv_ifp; - struct ieee80211com *ic = vap->iv_ic; - struct ifmediareq imr; - int maxrate; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, - "%s: %s parent %s flags 0x%x flags_ext 0x%x\n", - __func__, ieee80211_opmode_name[vap->iv_opmode], - ic->ic_name, vap->iv_flags, vap->iv_flags_ext); - - /* - * Do late attach work that cannot happen until after - * the driver has had a chance to override defaults. - */ - ieee80211_node_latevattach(vap); - ieee80211_power_latevattach(vap); - - maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, - vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat); - ieee80211_media_status(ifp, &imr); - /* NB: strip explicit mode; we're actually in autoselect */ - ifmedia_set(&vap->iv_media, - imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO)); - if (maxrate) - ifp->if_baudrate = IF_Mbps(maxrate); - - ether_ifattach(ifp, macaddr); - vap->iv_myaddr = IF_LLADDR(ifp); - /* hook output method setup by ether_ifattach */ - vap->iv_output = ifp->if_output; - ifp->if_output = ieee80211_output; - /* NB: if_mtu set by ether_ifattach to ETHERMTU */ - - IEEE80211_LOCK(ic); - TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); - ieee80211_syncflag_locked(ic, IEEE80211_F_WME); -#ifdef IEEE80211_SUPPORT_SUPERG - ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); -#endif - ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); - ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); - ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); - ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); - IEEE80211_UNLOCK(ic); - - return 1; -} - /* * Tear down vap state and reclaim the ifnet. * The driver is assumed to have prepared for @@ -748,7 +523,7 @@ ieee80211_allmulti(struct ieee80211vap *vap, bool * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. */ -static void +void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag) { struct ieee80211vap *vap; @@ -788,7 +563,7 @@ ieee80211_syncflag(struct ieee80211vap *vap, int f * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. */ -static void +void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag) { struct ieee80211vap *vap; @@ -828,7 +603,7 @@ ieee80211_syncflag_ht(struct ieee80211vap *vap, in * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. */ -static void +void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag) { struct ieee80211vap *vap; @@ -1095,140 +870,6 @@ ieee80211_lookup_channel_rxstatus(struct ieee80211 return (c); } -static void -addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword) -{ -#define ADD(_ic, _s, _o) \ - ifmedia_add(media, \ - IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) - static const u_int mopts[IEEE80211_MODE_MAX] = { - [IEEE80211_MODE_AUTO] = IFM_AUTO, - [IEEE80211_MODE_11A] = IFM_IEEE80211_11A, - [IEEE80211_MODE_11B] = IFM_IEEE80211_11B, - [IEEE80211_MODE_11G] = IFM_IEEE80211_11G, - [IEEE80211_MODE_FH] = IFM_IEEE80211_FH, - [IEEE80211_MODE_TURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, - [IEEE80211_MODE_TURBO_G] = IFM_IEEE80211_11G|IFM_IEEE80211_TURBO, - [IEEE80211_MODE_STURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, - [IEEE80211_MODE_HALF] = IFM_IEEE80211_11A, /* XXX */ - [IEEE80211_MODE_QUARTER] = IFM_IEEE80211_11A, /* XXX */ - [IEEE80211_MODE_11NA] = IFM_IEEE80211_11NA, - [IEEE80211_MODE_11NG] = IFM_IEEE80211_11NG, - }; - u_int mopt; - - mopt = mopts[mode]; - if (addsta) - ADD(ic, mword, mopt); /* STA mode has no cap */ - if (caps & IEEE80211_C_IBSS) - ADD(media, mword, mopt | IFM_IEEE80211_ADHOC); - if (caps & IEEE80211_C_HOSTAP) - ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP); - if (caps & IEEE80211_C_AHDEMO) - ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); - if (caps & IEEE80211_C_MONITOR) - ADD(media, mword, mopt | IFM_IEEE80211_MONITOR); - if (caps & IEEE80211_C_WDS) - ADD(media, mword, mopt | IFM_IEEE80211_WDS); - if (caps & IEEE80211_C_MBSS) - ADD(media, mword, mopt | IFM_IEEE80211_MBSS); -#undef ADD -} - -/* - * Setup the media data structures according to the channel and - * rate tables. - */ -static int -ieee80211_media_setup(struct ieee80211com *ic, - struct ifmedia *media, int caps, int addsta, - ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) -{ - int i, j, rate, maxrate, mword, r; - enum ieee80211_phymode mode; - const struct ieee80211_rateset *rs; - struct ieee80211_rateset allrates; - - /* - * Fill in media characteristics. - */ - ifmedia_init(media, 0, media_change, media_stat); - maxrate = 0; - /* - * Add media for legacy operating modes. - */ - memset(&allrates, 0, sizeof(allrates)); - for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { - if (isclr(ic->ic_modecaps, mode)) - continue; - addmedia(media, caps, addsta, mode, IFM_AUTO); - if (mode == IEEE80211_MODE_AUTO) - continue; - rs = &ic->ic_sup_rates[mode]; - for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i]; - mword = ieee80211_rate2media(ic, rate, mode); - if (mword == 0) - continue; - addmedia(media, caps, addsta, mode, mword); - /* - * Add legacy rate to the collection of all rates. - */ - r = rate & IEEE80211_RATE_VAL; - for (j = 0; j < allrates.rs_nrates; j++) - if (allrates.rs_rates[j] == r) - break; - if (j == allrates.rs_nrates) { - /* unique, add to the set */ - allrates.rs_rates[j] = r; - allrates.rs_nrates++; - } - rate = (rate & IEEE80211_RATE_VAL) / 2; - if (rate > maxrate) - maxrate = rate; - } - } - for (i = 0; i < allrates.rs_nrates; i++) { - mword = ieee80211_rate2media(ic, allrates.rs_rates[i], - IEEE80211_MODE_AUTO); - if (mword == 0) - continue; - /* NB: remove media options from mword */ - addmedia(media, caps, addsta, - IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword)); - } - /* - * Add HT/11n media. Note that we do not have enough - * bits in the media subtype to express the MCS so we - * use a "placeholder" media subtype and any fixed MCS - * must be specified with a different mechanism. - */ - for (; mode <= IEEE80211_MODE_11NG; mode++) { - if (isclr(ic->ic_modecaps, mode)) - continue; - addmedia(media, caps, addsta, mode, IFM_AUTO); - addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || - isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { - addmedia(media, caps, addsta, - IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); - i = ic->ic_txstream * 8 - 1; - if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && - (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) - rate = ieee80211_htrates[i].ht40_rate_400ns; - else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) - rate = ieee80211_htrates[i].ht40_rate_800ns; - else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) - rate = ieee80211_htrates[i].ht20_rate_400ns; - else - rate = ieee80211_htrates[i].ht20_rate_800ns; - if (rate > maxrate) - maxrate = rate; - } - return maxrate; -} - /* XXX inline or eliminate? */ const struct ieee80211_rateset * ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) Index: sys/net80211/ieee80211_ddb.c =================================================================== --- sys/net80211/ieee80211_ddb.c (revision 287554) +++ sys/net80211/ieee80211_ddb.c (working copy) @@ -634,7 +634,8 @@ _db_show_com(const struct ieee80211com *ic, int sh ic->ic_montaps, ic->ic_th, ic->ic_txchan, ic->ic_rh, ic->ic_rxchan); if (showprocs) { - DB_PRINTSYM("\t", "ic_vap_create", ic->ic_vap_create); + DB_PRINTSYM("\t", "ic_vap_preattach", ic->ic_vap_preattach); + DB_PRINTSYM("\t", "ic_vap_postattach", ic->ic_vap_postattach); DB_PRINTSYM("\t", "ic_vap_delete", ic->ic_vap_delete); #if 0 /* operating mode attachment */ Index: sys/net80211/ieee80211_freebsd.c =================================================================== --- sys/net80211/ieee80211_freebsd.c (revision 287554) +++ sys/net80211/ieee80211_freebsd.c (working copy) @@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); @@ -66,6 +68,181 @@ SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); +static void +addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword) +{ +#define ADD(_ic, _s, _o) \ + ifmedia_add(media, \ + IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) + static const u_int mopts[IEEE80211_MODE_MAX] = { + [IEEE80211_MODE_AUTO] = IFM_AUTO, + [IEEE80211_MODE_11A] = IFM_IEEE80211_11A, + [IEEE80211_MODE_11B] = IFM_IEEE80211_11B, + [IEEE80211_MODE_11G] = IFM_IEEE80211_11G, + [IEEE80211_MODE_FH] = IFM_IEEE80211_FH, + [IEEE80211_MODE_TURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, + [IEEE80211_MODE_TURBO_G] = IFM_IEEE80211_11G|IFM_IEEE80211_TURBO, + [IEEE80211_MODE_STURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO, + [IEEE80211_MODE_HALF] = IFM_IEEE80211_11A, /* XXX */ + [IEEE80211_MODE_QUARTER] = IFM_IEEE80211_11A, /* XXX */ + [IEEE80211_MODE_11NA] = IFM_IEEE80211_11NA, + [IEEE80211_MODE_11NG] = IFM_IEEE80211_11NG, + }; + u_int mopt; + + mopt = mopts[mode]; + if (addsta) + ADD(ic, mword, mopt); /* STA mode has no cap */ + if (caps & IEEE80211_C_IBSS) + ADD(media, mword, mopt | IFM_IEEE80211_ADHOC); + if (caps & IEEE80211_C_HOSTAP) + ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP); + if (caps & IEEE80211_C_AHDEMO) + ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); + if (caps & IEEE80211_C_MONITOR) + ADD(media, mword, mopt | IFM_IEEE80211_MONITOR); + if (caps & IEEE80211_C_WDS) + ADD(media, mword, mopt | IFM_IEEE80211_WDS); + if (caps & IEEE80211_C_MBSS) + ADD(media, mword, mopt | IFM_IEEE80211_MBSS); +#undef ADD +} + +/* + * Setup the media data structures according to the channel and + * rate tables. + */ +static int +ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, + int caps, int addsta) +{ + int i, j, rate, maxrate, mword, r; + enum ieee80211_phymode mode; + const struct ieee80211_rateset *rs; + struct ieee80211_rateset allrates; + + /* + * Fill in media characteristics. + */ + ifmedia_init(media, 0, + ic->ic_media_change ? ic->ic_media_change : ieee80211_media_change, + ic->ic_media_stat ? ic->ic_media_stat : ieee80211_media_status); + maxrate = 0; + /* + * Add media for legacy operating modes. + */ + memset(&allrates, 0, sizeof(allrates)); + for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { + if (isclr(ic->ic_modecaps, mode)) + continue; + addmedia(media, caps, addsta, mode, IFM_AUTO); + if (mode == IEEE80211_MODE_AUTO) + continue; + rs = &ic->ic_sup_rates[mode]; + for (i = 0; i < rs->rs_nrates; i++) { + rate = rs->rs_rates[i]; + mword = ieee80211_rate2media(ic, rate, mode); + if (mword == 0) + continue; + addmedia(media, caps, addsta, mode, mword); + /* + * Add legacy rate to the collection of all rates. + */ + r = rate & IEEE80211_RATE_VAL; + for (j = 0; j < allrates.rs_nrates; j++) + if (allrates.rs_rates[j] == r) + break; + if (j == allrates.rs_nrates) { + /* unique, add to the set */ + allrates.rs_rates[j] = r; + allrates.rs_nrates++; + } + rate = (rate & IEEE80211_RATE_VAL) / 2; + if (rate > maxrate) + maxrate = rate; + } + } + for (i = 0; i < allrates.rs_nrates; i++) { + mword = ieee80211_rate2media(ic, allrates.rs_rates[i], + IEEE80211_MODE_AUTO); + if (mword == 0) + continue; + /* NB: remove media options from mword */ + addmedia(media, caps, addsta, + IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword)); + } + /* + * Add HT/11n media. Note that we do not have enough + * bits in the media subtype to express the MCS so we + * use a "placeholder" media subtype and any fixed MCS + * must be specified with a different mechanism. + */ + for (; mode <= IEEE80211_MODE_11NG; mode++) { + if (isclr(ic->ic_modecaps, mode)) + continue; + addmedia(media, caps, addsta, mode, IFM_AUTO); + addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || + isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { + addmedia(media, caps, addsta, + IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); + i = ic->ic_txstream * 8 - 1; + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) + rate = ieee80211_htrates[i].ht40_rate_400ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) + rate = ieee80211_htrates[i].ht40_rate_800ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) + rate = ieee80211_htrates[i].ht20_rate_400ns; + else + rate = ieee80211_htrates[i].ht20_rate_800ns; + if (rate > maxrate) + maxrate = rate; + } + return maxrate; +} + +/* + * Default reset method for use with the ioctl support. This + * method is invoked after any state change in the 802.11 + * layer that should be propagated to the hardware but not + * require re-initialization of the 802.11 state machine (e.g + * rescanning for an ap). We always return ENETRESET which + * should cause the driver to re-initialize the device. Drivers + * can override this method to implement more optimized support. + */ +static int +default_reset(struct ieee80211vap *vap, u_long cmd) +{ + return ENETRESET; +} + +/* + * Add underlying device errors to vap errors. + */ +static uint64_t +ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt) +{ + struct ieee80211vap *vap = ifp->if_softc; + struct ieee80211com *ic = vap->iv_ic; + uint64_t rv; + + rv = if_get_counter_default(ifp, cnt); + switch (cnt) { + case IFCOUNTER_OERRORS: + rv += counter_u64_fetch(ic->ic_oerrors); + break; + case IFCOUNTER_IERRORS: + rv += counter_u64_fetch(ic->ic_ierrors); + break; + default: + break; + } + + return (rv); +} + static const char wlanname[] = "wlan"; static struct if_clone *wlan_cloner; @@ -73,9 +250,11 @@ static int wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) { struct ieee80211_clone_params cp; + struct ifmediareq imr; struct ieee80211vap *vap; struct ieee80211com *ic; - int error; + struct ifnet *ifp; + int maxrate, error; error = copyin(params, &cp, sizeof(cp)); if (error) @@ -103,12 +282,170 @@ wlan_clone_create(struct if_clone *ifc, int unit, ic_printf(ic, "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); + if (!TAILQ_EMPTY(&ic->ic_vaps) && + !(ic->ic_caps & IEEE80211_C_MULTIVAP)) { + ic_printf(ic, "can have only one interface configured"); + return (EBUSY); + } - return (vap == NULL ? EIO : 0); + if (ic->ic_vap_preattach && (error = + ic->ic_vap_preattach(ic, cp.icp_opmode, cp.icp_flags)) != 0) + return (error); + + vap = malloc(sizeof(struct ieee80211vap), M_80211_VAP, M_WAITOK | + M_ZERO); + ifp = if_alloc(IFT_ETHER); + KASSERT(ifp != NULL, ("%s: failed to allocate ifnet")); + + if_initname(ifp, wlanname, unit); + ifp->if_softc = vap; /* back pointer */ + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_transmit = ieee80211_vap_transmit; + ifp->if_qflush = ieee80211_vap_qflush; + ifp->if_ioctl = ieee80211_ioctl; + ifp->if_init = ieee80211_init; + ifp->if_get_counter = ieee80211_get_counter; + + vap->iv_ifp = ifp; + vap->iv_ic = ic; + vap->iv_flags = ic->ic_flags; /* propagate common flags */ + vap->iv_flags_ext = ic->ic_flags_ext; + vap->iv_flags_ven = ic->ic_flags_ven; + vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; + vap->iv_htcaps = ic->ic_htcaps; + vap->iv_htextcaps = ic->ic_htextcaps; + vap->iv_opmode = cp.icp_opmode; + vap->iv_caps |= ieee80211_opcap[cp.icp_opmode]; + switch (cp.icp_opmode) { + case IEEE80211_M_WDS: + /* + * WDS links must specify the bssid of the far end. + * For legacy operation this is a static relationship. + * For non-legacy operation the station must associate + * and be authorized to pass traffic. Plumbing the + * vap to the proper node happens when the vap + * transitions to RUN state. + */ + IEEE80211_ADDR_COPY(vap->iv_des_bssid, cp.icp_bssid); + vap->iv_flags |= IEEE80211_F_DESBSSID; + if (cp.icp_flags & IEEE80211_CLONE_WDSLEGACY) + vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY; + break; +#ifdef IEEE80211_SUPPORT_TDMA + case IEEE80211_M_AHDEMO: + if (cp.icp_flags & IEEE80211_CLONE_TDMA) { + /* NB: checked before clone operation allowed */ + KASSERT(ic->ic_caps & IEEE80211_C_TDMA, + ("not TDMA capable, ic_caps 0x%x", ic->ic_caps)); + /* + * Propagate TDMA capability to mark vap; this + * cannot be removed and is used to distinguish + * regular ahdemo operation from ahdemo+tdma. + */ + vap->iv_caps |= IEEE80211_C_TDMA; + } + break; +#endif + default: + break; + } + /* auto-enable s/w beacon miss support */ + if (cp.icp_flags & IEEE80211_CLONE_NOBEACONS) + vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS; + /* auto-generated or user supplied MAC address */ + if (cp.icp_flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR)) + vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC; + /* + * Enable various functionality by default if we're + * capable; the driver can override us if it knows better. + */ + if (vap->iv_caps & IEEE80211_C_WME) + vap->iv_flags |= IEEE80211_F_WME; + if (vap->iv_caps & IEEE80211_C_BURST) + vap->iv_flags |= IEEE80211_F_BURST; + /* NB: bg scanning only makes sense for station mode right now */ + if (vap->iv_opmode == IEEE80211_M_STA && + (vap->iv_caps & IEEE80211_C_BGSCAN)) + vap->iv_flags |= IEEE80211_F_BGSCAN; + vap->iv_flags |= IEEE80211_F_DOTH; /* XXX no cap, just ena */ + /* NB: DFS support only makes sense for ap mode right now */ + if (vap->iv_opmode == IEEE80211_M_HOSTAP && + (vap->iv_caps & IEEE80211_C_DFS)) + vap->iv_flags_ext |= IEEE80211_FEXT_DFS; + + vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ + vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; + vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; + /* + * Install a default reset method for the ioctl support; + * the driver can override this. + */ + vap->iv_reset = default_reset; + + ieee80211_sysctl_vattach(vap); + ieee80211_crypto_vattach(vap); + ieee80211_node_vattach(vap); + ieee80211_power_vattach(vap); + ieee80211_proto_vattach(vap); +#ifdef IEEE80211_SUPPORT_SUPERG + ieee80211_superg_vattach(vap); +#endif + ieee80211_ht_vattach(vap); + ieee80211_scan_vattach(vap); + ieee80211_regdomain_vattach(vap); + ieee80211_radiotap_vattach(vap); + ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE); + + /* + * Let device driver allocate its per-vap softc, and + * optionally override some vap methods. + */ + ic->ic_vap_postattach(ic, vap); + + /* Default to opmode of new vap. */ + ic->ic_opmode = cp.icp_opmode; + + /* + * Do late attach work that cannot happen until after + * the driver has had a chance to override defaults. + * + * XXXGL: the late attach requires iv_myaddr, so we + * need to temporarily set it. + */ + vap->iv_myaddr = cp.icp_flags & IEEE80211_CLONE_MACADDR ? + cp.icp_macaddr : ic->ic_macaddr; + ieee80211_node_latevattach(vap); + ieee80211_power_latevattach(vap); + + maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, + vap->iv_opmode == IEEE80211_M_STA); + ieee80211_media_status(ifp, &imr); + /* NB: strip explicit mode; we're actually in autoselect */ + ifmedia_set(&vap->iv_media, + imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO)); + if (maxrate) + ifp->if_baudrate = IF_Mbps(maxrate); + ether_ifattach(ifp, cp.icp_flags & IEEE80211_CLONE_MACADDR ? + cp.icp_macaddr : ic->ic_macaddr); + vap->iv_myaddr = IF_LLADDR(ifp); + /* hook output method setup by ether_ifattach */ + vap->iv_output = ifp->if_output; + ifp->if_output = ieee80211_output; + /* NB: if_mtu set by ether_ifattach to ETHERMTU */ + + IEEE80211_LOCK(ic); + TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); + ieee80211_syncflag_locked(ic, IEEE80211_F_WME); +#ifdef IEEE80211_SUPPORT_SUPERG + ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); +#endif + ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); + ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); + ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); + ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); + IEEE80211_UNLOCK(ic); + + return (0); } static void Index: sys/net80211/ieee80211_proto.h =================================================================== --- sys/net80211/ieee80211_proto.h (revision 287554) +++ sys/net80211/ieee80211_proto.h (working copy) @@ -61,6 +61,9 @@ void ieee80211_allmulti(struct ieee80211vap *, boo void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); +void ieee80211_syncflag_locked(struct ieee80211com *, int); +void ieee80211_syncflag_ht_locked(struct ieee80211com *, int); +void ieee80211_syncflag_ext_locked(struct ieee80211com *, int); #define IEEE80211_R_NF 0x0000001 /* global NF value valid */ #define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */ Index: sys/net80211/ieee80211_var.h =================================================================== --- sys/net80211/ieee80211_var.h (revision 287554) +++ sys/net80211/ieee80211_var.h (working copy) @@ -235,11 +235,10 @@ struct ieee80211com { int ic_montaps; /* active monitor mode taps */ /* virtual ap create/delete */ - struct ieee80211vap* (*ic_vap_create)(struct ieee80211com *, - const char [IFNAMSIZ], int, - enum ieee80211_opmode, int, - const uint8_t [IEEE80211_ADDR_LEN], - const uint8_t [IEEE80211_ADDR_LEN]); + int (*ic_vap_preattach)(struct ieee80211com *, + enum ieee80211_opmode, int); + void (*ic_vap_postattach)(struct ieee80211com *, + struct ieee80211vap *); void (*ic_vap_delete)(struct ieee80211vap *); /* device specific ioctls */ int (*ic_ioctl)(struct ieee80211com *, @@ -269,6 +268,10 @@ struct ieee80211com { int (*ic_raw_xmit)(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); + /* media change */ + ifm_change_cb_t ic_media_change; + ifm_stat_cb_t ic_media_stat; + /* update device state for 802.11 slot time change */ void (*ic_updateslot)(struct ieee80211com *); /* handle multicast state changes */ @@ -353,6 +356,7 @@ struct ieee80211_hwmp_state; struct ieee80211vap { struct ifmedia iv_media; /* interface media config */ struct ifnet *iv_ifp; /* associated device */ + void *iv_softc; /* driver's softc */ struct bpf_if *iv_rawbpf; /* packet filter structure */ struct sysctl_ctx_list *iv_sysctl; /* dynamic sysctl context */ struct sysctl_oid *iv_oid; /* net.wlan.X sysctl oid */ @@ -644,7 +648,8 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_C_DFS 0x00020000 /* CAPABILITY: DFS/radar avail*/ #define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */ #define IEEE80211_C_SWSLEEP 0x00080000 /* CAPABILITY: do sleep here */ -/* 0x7c0000 available */ +#define IEEE80211_C_MULTIVAP 0x00100000 /* CAPABILITY: > 1 vaps */ +/* 0x6c0000 available */ #define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ #define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ #define IEEE80211_C_WPA 0x01800000 /* CAPABILITY: WPA1+WPA2 avail*/ @@ -692,13 +697,6 @@ MALLOC_DECLARE(M_80211_VAP); int ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3); void ieee80211_ifattach(struct ieee80211com *); void ieee80211_ifdetach(struct ieee80211com *); -int ieee80211_vap_setup(struct ieee80211com *, struct ieee80211vap *, - const char name[IFNAMSIZ], int unit, - enum ieee80211_opmode opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN]); -int ieee80211_vap_attach(struct ieee80211vap *, - ifm_change_cb_t, ifm_stat_cb_t, - const uint8_t macaddr[IEEE80211_ADDR_LEN]); void ieee80211_vap_detach(struct ieee80211vap *); const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *); --mxv5cy4qt+RJ9ypb--