Mercurial > illumos > illumos-gate
changeset 8594:8ce911903616
6774031 iwk driver needs to support Ad-Hoc networking
author | fei feng - Sun Microsystems - Beijing China <Fei.Feng@Sun.COM> |
---|---|
date | Wed, 21 Jan 2009 16:12:41 +0800 |
parents | 09567ba33f63 |
children | ee750373956d |
files | usr/src/uts/common/io/iwk/iwk2.c usr/src/uts/common/io/iwk/iwk2_var.h usr/src/uts/common/io/net80211/net80211_input.c usr/src/uts/common/io/net80211/net80211_ioctl.c usr/src/uts/common/io/net80211/net80211_node.c usr/src/uts/common/io/net80211/net80211_output.c usr/src/uts/common/io/net80211/net80211_proto.c |
diffstat | 7 files changed, 965 insertions(+), 148 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/iwk/iwk2.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/iwk/iwk2.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -308,6 +308,8 @@ static int iwk_rx_sens(iwk_sc_t *sc); static int iwk_cck_sens(iwk_sc_t *sc, uint32_t actual_rx_time); static int iwk_ofdm_sens(iwk_sc_t *sc, uint32_t actual_rx_time); +static void iwk_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, + struct ieee80211_node *in, int subtype, int rssi, uint32_t rstamp); static void iwk_write_event_log(iwk_sc_t *); static void iwk_write_error_log(iwk_sc_t *); @@ -335,6 +337,11 @@ static void iwk_destroy_locks(iwk_sc_t *sc); static int iwk_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type); static void iwk_thread(iwk_sc_t *sc); +static int iwk_run_state_config_ibss(ieee80211com_t *ic); +static int iwk_run_state_config_sta(ieee80211com_t *ic); +static int iwk_start_tx_beacon(ieee80211com_t *ic); +static int iwk_clean_add_node_ibss(struct ieee80211com *ic, + uint8_t addr[IEEE80211_ADDR_LEN], uint8_t *index2); /* * Supported rates for 802.11b/g modes (in 500Kbps unit). @@ -561,6 +568,8 @@ DDI_INTR_PRI(sc->sc_intr_pri)); mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_pri)); + mutex_init(&sc->sc_ibss.node_tb_lock, NULL, MUTEX_DRIVER, + DDI_INTR_PRI(sc->sc_intr_pri)); cv_init(&sc->sc_fw_cv, NULL, CV_DRIVER, NULL); cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL); @@ -651,6 +660,10 @@ * Support WPA/WPA2 */ ic->ic_caps |= IEEE80211_C_WPA; + /* + * support Adhoc mode + */ + ic->ic_caps |= IEEE80211_C_IBSS; /* set supported .11b and .11g rates */ ic->ic_sup_rates[IEEE80211_MODE_11B] = iwk_rateset_11b; @@ -665,6 +678,7 @@ IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_PASSIVE; } + ic->ic_ibss_chan = &ic->ic_sup_channels[0]; ic->ic_xmit = iwk_send; /* @@ -685,6 +699,7 @@ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = iwk_newstate; sc->sc_recv_mgmt = ic->ic_recv_mgmt; + ic->ic_recv_mgmt = iwk_recv_mgmt; ic->ic_node_alloc = iwk_node_alloc; ic->ic_node_free = iwk_node_free; ic->ic_crypto.cs_key_set = iwk_key_set; @@ -727,7 +742,7 @@ IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr); macp = mac_alloc(MAC_VERSION); - if (err != DDI_SUCCESS) { + if (macp == NULL) { cmn_err(CE_WARN, "iwk_attach(): failed to do mac_alloc()\n"); goto attach_fail9; @@ -1620,48 +1635,30 @@ } IWK_DBG((IWK_DEBUG_80211, "iwk: associated.")); + /* IBSS mode */ + if (ic->ic_opmode == IEEE80211_M_IBSS) { + /* + * clean all nodes in ibss node table + * in order to be consistent with hardware + */ + err = iwk_run_state_config_ibss(ic); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_newstate(): " + "failed to update configuration " + "in IBSS mode\n"); + mutex_exit(&sc->sc_glock); + return (err); + } + } + /* none IBSS mode */ if (ic->ic_opmode != IEEE80211_M_IBSS) { /* update adapter's configuration */ - if (sc->sc_assoc_id != in->in_associd) { - cmn_err(CE_WARN, - "associate ID mismatch: expected %d, " - "got %d\n", - in->in_associd, sc->sc_assoc_id); - } - sc->sc_config.assoc_id = in->in_associd & 0x3fff; - /* - * short preamble/slot time are - * negotiated when associating - */ - sc->sc_config.flags &= - ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK | - RXON_FLG_SHORT_SLOT_MSK); - - if (ic->ic_flags & IEEE80211_F_SHSLOT) - sc->sc_config.flags |= - LE_32(RXON_FLG_SHORT_SLOT_MSK); - - if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - sc->sc_config.flags |= - LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); - - sc->sc_config.filter_flags |= - LE_32(RXON_FILTER_ASSOC_MSK); - - if (ic->ic_opmode != IEEE80211_M_STA) - sc->sc_config.filter_flags |= - LE_32(RXON_FILTER_BCON_AWARE_MSK); - - IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x" - " filter_flags %x\n", - sc->sc_config.chan, sc->sc_config.flags, - sc->sc_config.filter_flags)); - err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config, - sizeof (iwk_rxon_cmd_t), 1); + err = iwk_run_state_config_sta(ic); if (err != IWK_SUCCESS) { - cmn_err(CE_WARN, "could not update " - "configuration\n"); + cmn_err(CE_WARN, "iwk_newstate(): " + "failed to update configuration " + "in none IBSS mode\n"); mutex_exit(&sc->sc_glock); return (err); } @@ -1678,9 +1675,24 @@ if (err) { cmn_err(CE_WARN, "iwk_newstate(): " "failed to set tx power table\n"); + mutex_exit(&sc->sc_glock); return (err); } + if (ic->ic_opmode == IEEE80211_M_IBSS) { + + /* + * allocate and transmit beacon frames + */ + err = iwk_start_tx_beacon(ic); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_newstate(): " + "can't transmit beacon frames\n"); + mutex_exit(&sc->sc_glock); + return (err); + } + } + /* start automatic rate control */ mutex_enter(&sc->sc_mt_lock); if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { @@ -1758,6 +1770,7 @@ iwk_sc_t *sc = (iwk_sc_t *)ic; iwk_add_sta_t node; int err; + uint8_t index1; switch (k->wk_cipher->ic_cipher) { case IEEE80211_CIPHER_WEP: @@ -1778,6 +1791,66 @@ if (IEEE80211_IS_MULTICAST(mac)) { (void) memset(node.bssid, 0xff, 6); node.id = IWK_BROADCAST_ID; + } else if (ic->ic_opmode == IEEE80211_M_IBSS) { + mutex_exit(&sc->sc_glock); + mutex_enter(&sc->sc_ibss.node_tb_lock); + + /* + * search for node in ibss node table + */ + for (index1 = IWK_STA_ID; index1 < IWK_STATION_COUNT; + index1++) { + if (sc->sc_ibss.ibss_node_tb[index1].used && + IEEE80211_ADDR_EQ(sc->sc_ibss. + ibss_node_tb[index1].node.bssid, + mac)) { + break; + } + } + if (index1 >= IWK_BROADCAST_ID) { + cmn_err(CE_WARN, "iwk_key_set(): " + "have no this node in hardware node table\n"); + mutex_exit(&sc->sc_ibss.node_tb_lock); + return (0); + } else { + /* + * configure key for given node in hardware + */ + if (k->wk_flags & IEEE80211_KEY_XMIT) { + sc->sc_ibss.ibss_node_tb[index1]. + node.key_flags = 0; + sc->sc_ibss.ibss_node_tb[index1]. + node.keyp = k->wk_keyix; + } else { + sc->sc_ibss.ibss_node_tb[index1]. + node.key_flags = (1 << 14); + sc->sc_ibss.ibss_node_tb[index1]. + node.keyp = k->wk_keyix + 4; + } + + (void) memcpy(sc->sc_ibss.ibss_node_tb[index1].node.key, + k->wk_key, k->wk_keylen); + sc->sc_ibss.ibss_node_tb[index1].node.key_flags |= + (STA_KEY_FLG_CCMP | (1 << 3) | (k->wk_keyix << 8)); + sc->sc_ibss.ibss_node_tb[index1].node.sta_mask = + STA_MODIFY_KEY_MASK; + sc->sc_ibss.ibss_node_tb[index1].node.control = 1; + + mutex_enter(&sc->sc_glock); + err = iwk_cmd(sc, REPLY_ADD_STA, + &sc->sc_ibss.ibss_node_tb[index1].node, + sizeof (iwk_add_sta_t), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_key_set(): " + "failed to update IBSS node in hardware\n"); + mutex_exit(&sc->sc_glock); + mutex_exit(&sc->sc_ibss.node_tb_lock); + return (0); + } + mutex_exit(&sc->sc_glock); + } + mutex_exit(&sc->sc_ibss.node_tb_lock); + return (1); } else { IEEE80211_ADDR_COPY(node.bssid, ic->ic_bss->in_bssid); node.id = IWK_AP_ID; @@ -2497,6 +2570,7 @@ mblk_t *m, *m0; int rate, hdrlen, len, len0, mblen, off, err = IWK_SUCCESS; uint16_t masks = 0; + uint8_t index, index1, index2; ring = &sc->sc_txq[0]; data = &ring->data[ring->cur]; @@ -2550,6 +2624,49 @@ wh = (struct ieee80211_frame *)m->b_rptr; + if (ic->ic_opmode == IEEE80211_M_IBSS && + (!(IEEE80211_IS_MULTICAST(wh->i_addr1)))) { + mutex_enter(&sc->sc_glock); + mutex_enter(&sc->sc_ibss.node_tb_lock); + + /* + * search for node in ibss node table + */ + for (index1 = IWK_STA_ID; + index1 < IWK_STATION_COUNT; index1++) { + if (sc->sc_ibss.ibss_node_tb[index1].used && + IEEE80211_ADDR_EQ(sc->sc_ibss. + ibss_node_tb[index1].node.bssid, + wh->i_addr1)) { + break; + } + } + + /* + * if don't find in ibss node table + */ + if (index1 >= IWK_BROADCAST_ID) { + err = iwk_clean_add_node_ibss(ic, + wh->i_addr1, &index2); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_send(): " + "failed to clean all nodes " + "and add one node\n"); + mutex_exit(&sc->sc_ibss.node_tb_lock); + mutex_exit(&sc->sc_glock); + freemsg(m); + sc->sc_tx_err++; + err = IWK_SUCCESS; + goto exit; + } + index = index2; + } else { + index = index1; + } + mutex_exit(&sc->sc_ibss.node_tb_lock); + mutex_exit(&sc->sc_glock); + } + in = ieee80211_find_txnode(ic, wh->i_addr1); if (in == NULL) { cmn_err(CE_WARN, "iwk_send(): failed to find tx node\n"); @@ -2640,7 +2757,9 @@ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { tx->sta_id = IWK_BROADCAST_ID; } else { - if (ic->ic_opmode != IEEE80211_M_IBSS) + if (ic->ic_opmode == IEEE80211_M_IBSS) + tx->sta_id = index; + else tx->sta_id = IWK_AP_ID; } @@ -2740,7 +2859,15 @@ { iwk_sc_t *sc = (iwk_sc_t *)arg; ieee80211com_t *ic = &sc->sc_ic; - int err; + + enum ieee80211_opmode oldmod; + iwk_tx_power_table_cmd_t txpower; + iwk_add_sta_t node; + iwk_link_quality_cmd_t link_quality; + uint16_t masks = 0; + int i, err, err1; + + oldmod = ic->ic_opmode; mutex_enter(&sc->sc_glock); if (sc->sc_flags & (IWK_F_SUSPEND | IWK_F_HW_ERR_RECOVER)) { @@ -2752,6 +2879,125 @@ err = ieee80211_ioctl(ic, wq, mp); + /* + * return to STA mode + */ + if ((0 == err || ENETRESET == err) && (oldmod != ic->ic_opmode) && + (ic->ic_opmode == IEEE80211_M_STA)) { + /* configure rxon */ + (void) memset(&sc->sc_config, 0, sizeof (iwk_rxon_cmd_t)); + IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr); + IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr); + sc->sc_config.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); + sc->sc_config.flags = (RXON_FLG_TSF2HOST_MSK | + RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_BAND_24G_MSK); + sc->sc_config.flags &= (~RXON_FLG_CCK_MSK); + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + sc->sc_config.dev_type = RXON_DEV_TYPE_ESS; + sc->sc_config.filter_flags |= + LE_32(RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_DIS_DECRYPT_MSK | + RXON_FILTER_DIS_GRP_DECRYPT_MSK); + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS; + sc->sc_config.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + sc->sc_config.filter_flags = + LE_32(RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_DIS_DECRYPT_MSK | + RXON_FILTER_DIS_GRP_DECRYPT_MSK); + break; + case IEEE80211_M_HOSTAP: + sc->sc_config.dev_type = RXON_DEV_TYPE_AP; + break; + case IEEE80211_M_MONITOR: + sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER; + sc->sc_config.filter_flags |= + LE_32(RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_CTL2HOST_MSK | + RXON_FILTER_PROMISC_MSK); + break; + } + sc->sc_config.cck_basic_rates = 0x0f; + sc->sc_config.ofdm_basic_rates = 0xff; + sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff; + sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff; + /* set antenna */ + mutex_enter(&sc->sc_glock); + sc->sc_config.rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | + LE_16((0x7 << RXON_RX_CHAIN_VALID_POS) | + (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) | + (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); + err1 = iwk_cmd(sc, REPLY_RXON, &sc->sc_config, + sizeof (iwk_rxon_cmd_t), 1); + if (err1 != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_m_ioctl(): " + "failed to set configure command" + " please run (ifconfig unplumb and" + " ifconfig plumb)\n"); + } + /* + * set Tx power for 2.4GHz channels + * (need further investigation. fix tx power at present) + */ + (void) memset(&txpower, 0, sizeof (txpower)); + txpower.band = 1; /* for 2.4G */ + txpower.channel = sc->sc_config.chan; + txpower.channel_normal_width = 0; + for (i = 0; i < POWER_TABLE_NUM_HT_OFDM_ENTRIES; i++) { + txpower.tx_power.ht_ofdm_power[i]. + s.ramon_tx_gain = 0x3f3f; + txpower.tx_power.ht_ofdm_power[i]. + s.dsp_predis_atten = 110 | (110 << 8); + } + txpower.tx_power.ht_ofdm_power[POWER_TABLE_NUM_HT_OFDM_ENTRIES]. + s.ramon_tx_gain = 0x3f3f; + txpower.tx_power.ht_ofdm_power[POWER_TABLE_NUM_HT_OFDM_ENTRIES]. + s.dsp_predis_atten = 110 | (110 << 8); + err1 = iwk_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower, + sizeof (txpower), 1); + if (err1 != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_m_ioctl(): failed to set txpower" + " please run (ifconfig unplumb " + "and ifconfig plumb)\n"); + } + /* add broadcast node so that we can send broadcast frame */ + (void) memset(&node, 0, sizeof (node)); + (void) memset(node.bssid, 0xff, 6); + node.id = IWK_BROADCAST_ID; + err1 = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1); + if (err1 != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_m_ioctl(): " + "failed to add broadcast node\n"); + } + + /* TX_LINK_QUALITY cmd */ + (void) memset(&link_quality, 0, sizeof (link_quality)); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + masks |= RATE_MCS_CCK_MSK; + masks |= RATE_MCS_ANT_B_MSK; + masks &= ~RATE_MCS_ANT_A_MSK; + link_quality.rate_n_flags[i] = + iwk_rate_to_plcp(2) | masks; + } + link_quality.general_params.single_stream_ant_msk = 2; + link_quality.general_params.dual_stream_ant_msk = 3; + link_quality.agg_params.agg_dis_start_th = 3; + link_quality.agg_params.agg_time_limit = LE_16(4000); + link_quality.sta_id = IWK_BROADCAST_ID; + err1 = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality, + sizeof (link_quality), 1); + if (err1 != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_m_ioctl(): " + "failed to config link quality table\n"); + } + mutex_exit(&sc->sc_glock); + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); + } + if (err == ENETRESET) { /* * This is special for the hidden AP connection. @@ -3252,7 +3498,7 @@ return (err); } - /* TX_LINK_QUALITY cmd ? */ + /* TX_LINK_QUALITY cmd */ (void) memset(&link_quality, 0, sizeof (link_quality)); rs = ic->ic_sup_rates[ieee80211_chan2mode(ic, ic->ic_curchan)]; for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { @@ -3505,6 +3751,7 @@ RXON_FILTER_DIS_DECRYPT_MSK | RXON_FILTER_DIS_GRP_DECRYPT_MSK); break; + case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS; sc->sc_config.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; @@ -5488,6 +5735,79 @@ } /* + * additional process to management frames + */ +static void iwk_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, + struct ieee80211_node *in, + int subtype, int rssi, uint32_t rstamp) +{ + iwk_sc_t *sc = (iwk_sc_t *)ic; + struct ieee80211_frame *wh; + uint8_t index1, index2; + int err; + + sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp); + + mutex_enter(&sc->sc_glock); + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BEACON: + if (sc->sc_ibss.ibss_beacon.syncbeacon && in == ic->ic_bss && + ic->ic_state == IEEE80211_S_RUN) { + if (ieee80211_beacon_update(ic, in, + &sc->sc_ibss.ibss_beacon.iwk_boff, + sc->sc_ibss.ibss_beacon.mp, 0)) { + bcopy(sc->sc_ibss.ibss_beacon.mp->b_rptr, + sc->sc_ibss.ibss_beacon.beacon_cmd. + bcon_frame, + MBLKL(sc->sc_ibss.ibss_beacon.mp)); + } + err = iwk_cmd(sc, REPLY_TX_BEACON, + &sc->sc_ibss.ibss_beacon.beacon_cmd, + sc->sc_ibss.ibss_beacon.beacon_cmd_len, 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_recv_mgmt(): " + "failed to TX beacon.\n"); + } + sc->sc_ibss.ibss_beacon.syncbeacon = 0; + } + if (ic->ic_opmode == IEEE80211_M_IBSS && + ic->ic_state == IEEE80211_S_RUN) { + wh = (struct ieee80211_frame *)mp->b_rptr; + mutex_enter(&sc->sc_ibss.node_tb_lock); + /* + * search for node in ibss node table + */ + for (index1 = IWK_STA_ID; index1 < IWK_STATION_COUNT; + index1++) { + if (sc->sc_ibss.ibss_node_tb[index1].used && + IEEE80211_ADDR_EQ(sc->sc_ibss. + ibss_node_tb[index1].node.bssid, + wh->i_addr2)) { + break; + } + } + /* + * if don't find in ibss node table + */ + if (index1 >= IWK_BROADCAST_ID) { + err = iwk_clean_add_node_ibss(ic, + wh->i_addr2, &index2); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_recv_mgmt(): " + "failed to clean all nodes " + "and add one node\n"); + } + } + mutex_exit(&sc->sc_ibss.node_tb_lock); + } + break; + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + break; + } + mutex_exit(&sc->sc_glock); +} + +/* * 1) log_event_table_ptr indicates base of the event log. This traces * a 256-entry history of uCode execution within a circular buffer. * Its header format is: @@ -5673,3 +5993,405 @@ iwk_mac_access_exit(sc); } + +static int +iwk_run_state_config_ibss(ieee80211com_t *ic) +{ + iwk_sc_t *sc = (iwk_sc_t *)ic; + ieee80211_node_t *in = ic->ic_bss; + int i, err = IWK_SUCCESS; + + mutex_enter(&sc->sc_ibss.node_tb_lock); + + /* + * clean all nodes in ibss node table assure be + * consistent with hardware + */ + for (i = IWK_STA_ID; i < IWK_STATION_COUNT; i++) { + sc->sc_ibss.ibss_node_tb[i].used = 0; + (void) memset(&sc->sc_ibss.ibss_node_tb[i].node, + 0, + sizeof (iwk_add_sta_t)); + } + + sc->sc_ibss.node_number = 0; + + mutex_exit(&sc->sc_ibss.node_tb_lock); + + /* + * configure RX and TX + */ + sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS; + + sc->sc_config.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + sc->sc_config.filter_flags = + LE_32(RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_DIS_DECRYPT_MSK | + RXON_FILTER_DIS_GRP_DECRYPT_MSK); + + sc->sc_config.assoc_id = 0; + + IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid); + sc->sc_config.chan = ieee80211_chan2ieee(ic, + in->in_chan); + + if (ic->ic_curmode == IEEE80211_MODE_11B) { + sc->sc_config.cck_basic_rates = 0x03; + sc->sc_config.ofdm_basic_rates = 0; + } else if ((in->in_chan != IEEE80211_CHAN_ANYC) && + (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) { + sc->sc_config.cck_basic_rates = 0; + sc->sc_config.ofdm_basic_rates = 0x15; + + } else { + sc->sc_config.cck_basic_rates = 0x0f; + sc->sc_config.ofdm_basic_rates = 0xff; + } + + sc->sc_config.flags &= + ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK | + RXON_FLG_SHORT_SLOT_MSK); + + if (ic->ic_flags & IEEE80211_F_SHSLOT) { + sc->sc_config.flags |= + LE_32(RXON_FLG_SHORT_SLOT_MSK); + } + + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) { + sc->sc_config.flags |= + LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); + } + + sc->sc_config.filter_flags |= + LE_32(RXON_FILTER_ASSOC_MSK); + + err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config, + sizeof (iwk_rxon_cmd_t), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_run_state_config_ibss(): " + "failed to update configuration.\n"); + return (err); + } + + return (err); + +} + +static int +iwk_run_state_config_sta(ieee80211com_t *ic) +{ + iwk_sc_t *sc = (iwk_sc_t *)ic; + ieee80211_node_t *in = ic->ic_bss; + int err = IWK_SUCCESS; + + /* update adapter's configuration */ + if (sc->sc_assoc_id != in->in_associd) { + cmn_err(CE_WARN, "iwk_run_state_config_sta(): " + "associate ID mismatch: expected %d, " + "got %d\n", + in->in_associd, sc->sc_assoc_id); + } + sc->sc_config.assoc_id = in->in_associd & 0x3fff; + + /* + * short preamble/slot time are + * negotiated when associating + */ + sc->sc_config.flags &= + ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK | + RXON_FLG_SHORT_SLOT_MSK); + + if (ic->ic_flags & IEEE80211_F_SHSLOT) + sc->sc_config.flags |= + LE_32(RXON_FLG_SHORT_SLOT_MSK); + + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + sc->sc_config.flags |= + LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); + + sc->sc_config.filter_flags |= + LE_32(RXON_FILTER_ASSOC_MSK); + + if (ic->ic_opmode != IEEE80211_M_STA) + sc->sc_config.filter_flags |= + LE_32(RXON_FILTER_BCON_AWARE_MSK); + + IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x" + " filter_flags %x\n", + sc->sc_config.chan, sc->sc_config.flags, + sc->sc_config.filter_flags)); + + err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config, + sizeof (iwk_rxon_cmd_t), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_run_state_config_sta(): " + "failed to update configuration\n"); + return (err); + } + + return (err); +} + +static int +iwk_start_tx_beacon(ieee80211com_t *ic) +{ + iwk_sc_t *sc = (iwk_sc_t *)ic; + ieee80211_node_t *in = ic->ic_bss; + int err = IWK_SUCCESS; + iwk_tx_beacon_cmd_t *tx_beacon_p; + uint16_t masks = 0; + mblk_t *mp; + int rate; + + /* + * allocate and transmit beacon frames + */ + tx_beacon_p = &sc->sc_ibss.ibss_beacon.beacon_cmd; + + (void) memset(tx_beacon_p, 0, + sizeof (iwk_tx_beacon_cmd_t)); + rate = 0; + masks = 0; + + tx_beacon_p->config.sta_id = IWK_BROADCAST_ID; + tx_beacon_p->config.stop_time.life_time = + LE_32(0xffffffff); + + if (sc->sc_ibss.ibss_beacon.mp != NULL) { + freemsg(sc->sc_ibss.ibss_beacon.mp); + sc->sc_ibss.ibss_beacon.mp = NULL; + } + + sc->sc_ibss.ibss_beacon.mp = + ieee80211_beacon_alloc(ic, in, + &sc->sc_ibss.ibss_beacon.iwk_boff); + if (sc->sc_ibss.ibss_beacon.mp == NULL) { + cmn_err(CE_WARN, "iwk_start_tx_beacon(): " + "failed to get beacon frame.\n"); + return (IWK_FAIL); + } + + mp = sc->sc_ibss.ibss_beacon.mp; + + ASSERT(mp->b_cont == NULL); + + bcopy(mp->b_rptr, tx_beacon_p->bcon_frame, MBLKL(mp)); + + tx_beacon_p->config.len = (uint16_t)(MBLKL(mp)); + sc->sc_ibss.ibss_beacon.beacon_cmd_len = + sizeof (iwk_tx_cmd_t) + + 4 + tx_beacon_p->config.len; + + /* + * beacons are sent at 1M + */ + rate = in->in_rates.ir_rates[0]; + rate &= IEEE80211_RATE_VAL; + + if (2 == rate || 4 == rate || 11 == rate || + 22 == rate) { + masks |= RATE_MCS_CCK_MSK; + } + + masks |= RATE_MCS_ANT_B_MSK; + + tx_beacon_p->config.rate.r.rate_n_flags = + (iwk_rate_to_plcp(rate) | masks); + + + tx_beacon_p->config.tx_flags = + (TX_CMD_FLG_SEQ_CTL_MSK | TX_CMD_FLG_TSF_MSK); + + if (ic->ic_bss->in_tstamp.tsf != 0) { + sc->sc_ibss.ibss_beacon.syncbeacon = 1; + } else { + if (ieee80211_beacon_update(ic, in, + &sc->sc_ibss.ibss_beacon.iwk_boff, + mp, 0)) { + bcopy(mp->b_rptr, + tx_beacon_p->bcon_frame, + MBLKL(mp)); + } + + err = iwk_cmd(sc, REPLY_TX_BEACON, + tx_beacon_p, + sc->sc_ibss.ibss_beacon.beacon_cmd_len, + 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_start_tx_beacon(): " + "failed to TX beacon.\n"); + return (err); + } + + sc->sc_ibss.ibss_beacon.syncbeacon = 0; + } + + return (err); +} + +static int +iwk_clean_add_node_ibss(struct ieee80211com *ic, + uint8_t addr[IEEE80211_ADDR_LEN], uint8_t *index2) +{ + iwk_sc_t *sc = (iwk_sc_t *)ic; + uint8_t index; + iwk_add_sta_t bc_node; + iwk_link_quality_cmd_t bc_link_quality; + iwk_link_quality_cmd_t link_quality; + uint16_t bc_masks = 0; + uint16_t masks = 0; + int i, rate; + struct ieee80211_rateset rs; + iwk_ibss_node_t *ibss_node_p; + int err = IWK_SUCCESS; + + /* + * find a location that is not + * used in ibss node table + */ + for (index = IWK_STA_ID; + index < IWK_STATION_COUNT; index++) { + if (!sc->sc_ibss.ibss_node_tb[index].used) { + break; + } + } + + /* + * if have too many nodes in hardware, clean up + */ + if (index < IWK_BROADCAST_ID && + sc->sc_ibss.node_number >= 25) { + if (iwk_cmd(sc, REPLY_REMOVE_ALL_STA, + NULL, 0, 1) != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "failed to remove all nodes in hardware\n"); + return (IWK_FAIL); + } + + for (i = IWK_STA_ID; i < IWK_STATION_COUNT; i++) { + sc->sc_ibss.ibss_node_tb[i].used = 0; + (void) memset(&sc->sc_ibss.ibss_node_tb[i].node, + 0, sizeof (iwk_add_sta_t)); + } + + sc->sc_ibss.node_number = 0; + + /* + * add broadcast node so that we + * can send broadcast frame + */ + (void) memset(&bc_node, 0, sizeof (bc_node)); + (void) memset(bc_node.bssid, 0xff, 6); + bc_node.id = IWK_BROADCAST_ID; + + err = iwk_cmd(sc, REPLY_ADD_STA, &bc_node, sizeof (bc_node), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "failed to add broadcast node\n"); + return (err); + } + + /* TX_LINK_QUALITY cmd */ + (void) memset(&bc_link_quality, 0, sizeof (bc_link_quality)); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + bc_masks |= RATE_MCS_CCK_MSK; + bc_masks |= RATE_MCS_ANT_B_MSK; + bc_masks &= ~RATE_MCS_ANT_A_MSK; + bc_link_quality.rate_n_flags[i] = + iwk_rate_to_plcp(2) | bc_masks; + } + + bc_link_quality.general_params.single_stream_ant_msk = 2; + bc_link_quality.general_params.dual_stream_ant_msk = 3; + bc_link_quality.agg_params.agg_dis_start_th = 3; + bc_link_quality.agg_params.agg_time_limit = LE_16(4000); + bc_link_quality.sta_id = IWK_BROADCAST_ID; + + err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, + &bc_link_quality, sizeof (bc_link_quality), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "failed to config link quality table\n"); + return (err); + } + } + + if (index >= IWK_BROADCAST_ID) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "the count of node in hardware is too much\n"); + return (IWK_FAIL); + } + + /* + * add a node into hardware + */ + ibss_node_p = &sc->sc_ibss.ibss_node_tb[index]; + + ibss_node_p->used = 1; + + (void) memset(&ibss_node_p->node, 0, + sizeof (iwk_add_sta_t)); + + IEEE80211_ADDR_COPY(ibss_node_p->node.bssid, addr); + ibss_node_p->node.id = index; + ibss_node_p->node.control = 0; + ibss_node_p->node.flags = 0; + + err = iwk_cmd(sc, REPLY_ADD_STA, &ibss_node_p->node, + sizeof (iwk_add_sta_t), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "failed to add IBSS node\n"); + ibss_node_p->used = 0; + (void) memset(&ibss_node_p->node, 0, + sizeof (iwk_add_sta_t)); + return (err); + } + + sc->sc_ibss.node_number++; + + (void) memset(&link_quality, 0, sizeof (link_quality)); + + rs = ic->ic_sup_rates[ieee80211_chan2mode(ic, + ic->ic_curchan)]; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + if (i < rs.ir_nrates) { + rate = rs. + ir_rates[rs.ir_nrates - i]; + } else { + rate = 2; + } + + if (2 == rate || 4 == rate || + 11 == rate || 22 == rate) { + masks |= RATE_MCS_CCK_MSK; + } + + masks |= RATE_MCS_ANT_B_MSK; + masks &= ~RATE_MCS_ANT_A_MSK; + + link_quality.rate_n_flags[i] = + iwk_rate_to_plcp(rate) | masks; + } + + link_quality.general_params.single_stream_ant_msk = 2; + link_quality.general_params.dual_stream_ant_msk = 3; + link_quality.agg_params.agg_dis_start_th = 3; + link_quality.agg_params.agg_time_limit = LE_16(4000); + link_quality.sta_id = ibss_node_p->node.id; + + err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, + &link_quality, sizeof (link_quality), 1); + if (err != IWK_SUCCESS) { + cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): " + "failed to set up TX link quality\n"); + ibss_node_p->used = 0; + (void) memset(ibss_node_p->node.bssid, 0, 6); + return (err); + } + + *index2 = index; + + return (err); +}
--- a/usr/src/uts/common/io/iwk/iwk2_var.h Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/iwk/iwk2_var.h Wed Jan 21 16:12:41 2009 +0800 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -90,6 +90,28 @@ int recovery; } iwk_amrr_t; +typedef struct iwk_ibss_node { + iwk_add_sta_t node; + int8_t used; +} iwk_ibss_node_t; + +typedef struct iwk_ibss_beacon { + /* for update beacon frame dynamically */ + struct ieee80211_beacon_offsets iwk_boff; + uint32_t beacon_cmd_len; + iwk_tx_beacon_cmd_t beacon_cmd; + uint8_t syncbeacon; + /* beacon frame allocated from net80211 module */ + mblk_t *mp; +} iwk_ibss_beacon_t; + +typedef struct iwk_ibss { + iwk_ibss_node_t ibss_node_tb[IWK_STATION_COUNT]; + uint32_t node_number; + kmutex_t node_tb_lock; + iwk_ibss_beacon_t ibss_beacon; +} iwk_ibss_t; + typedef struct iwk_softc { struct ieee80211com sc_ic; dev_info_t *sc_dip; @@ -174,6 +196,7 @@ uint32_t sc_tx_err; uint32_t sc_rx_err; uint32_t sc_tx_retries; + iwk_ibss_t sc_ibss; } iwk_sc_t; #define IWK_F_ATTACHED (1 << 0)
--- a/usr/src/uts/common/io/net80211/net80211_input.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/net80211/net80211_input.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,11 +1,11 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,6 +73,7 @@ uint8_t tid; ASSERT(in != NULL); + in->in_inact = in->in_inact_reload; type = (uint8_t)-1; /* undefined */ len = MBLKL(mp); if (len < sizeof (struct ieee80211_frame_min)) { @@ -179,7 +180,6 @@ } in->in_rxseqs[tid] = rxseq; } - in->in_inact = 0; } switch (type) { @@ -879,24 +879,21 @@ return; } - if (scan.capinfo & IEEE80211_CAPINFO_IBSS) { + if (ic->ic_opmode == IEEE80211_M_IBSS && + scan.capinfo & IEEE80211_CAPINFO_IBSS) { if (!IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) { /* * Create a new entry in the neighbor table. */ in = ieee80211_add_neighbor(ic, wh, &scan); - } else if (in->in_capinfo == 0) { + } else { /* - * Update faked node created on transmit. - * Note this also updates the tsf. + * Copy data from beacon to neighbor table. + * Some of this information might change after + * ieee80211_add_neighbor(), so we just copy + * everything over to be safe. */ ieee80211_init_neighbor(in, wh, &scan); - } else { - /* - * Record tsf for potential resync. - */ - bcopy(scan.tstamp, in->in_tstamp.data, - sizeof (in->in_tstamp)); } if (in != NULL) { in->in_rssi = (uint8_t)rssi; @@ -969,14 +966,20 @@ frm += frm[1] + 2; } IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break); + if (xrates != NULL) { + IEEE80211_VERIFY_ELEMENT(xrates, + IEEE80211_RATE_MAXSIZE - rates[1], break); + } IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, break); IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, break); - if ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) { - ieee80211_dbg(IEEE80211_MSG_INPUT, - "ieee80211_recv_mgmt: ignore %s, " - "no ssid with ssid suppression enabled", - IEEE80211_SUBTYPE_NAME(subtype)); - break; + if (ic->ic_flags & IEEE80211_F_HIDESSID) { + if (ssid == NULL || ssid[1] == 0) { + ieee80211_dbg(IEEE80211_MSG_INPUT, + "ieee80211_recv_mgmt: ignore %s, " + "no ssid with ssid suppression enabled", + IEEE80211_SUBTYPE_NAME(subtype)); + break; + } } if (in == ic->ic_bss) {
--- a/usr/src/uts/common/io/net80211/net80211_ioctl.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/net80211/net80211_ioctl.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -462,6 +462,9 @@ wl_get_bsstype(ic, ow_opmode); break; case WLAN_SET_PARAM: + if (*iw_opmode == ic->ic_opmode) + break; + err = wl_set_bsstype(ic, iw_opmode); break; default: @@ -477,6 +480,64 @@ } static int +wifi_cfg_createibss(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) +{ + mblk_t *omp; + wldp_t *inp = (wldp_t *)(*mp)->b_rptr; + wldp_t *outp; + wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)inp->wldp_buf; + wl_create_ibss_t *ow_ibss; + int err = 0; + + if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_create_ibss_t))) == NULL) + return (ENOMEM); + outp = (wldp_t *)omp->b_rptr; + ow_ibss = (wl_create_ibss_t *)outp->wldp_buf; + + switch (cmd) { + case WLAN_GET_PARAM: + *ow_ibss = (ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0; + break; + case WLAN_SET_PARAM: + ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_createibss: " + "set createibss=%u\n", *iw_ibss); + if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) { + outp->wldp_result = WL_LACK_FEATURE; + err = ENOTSUP; + break; + } + if (*iw_ibss) { /* create ibss */ + if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { + ic->ic_flags |= IEEE80211_F_IBSSON; + ic->ic_opmode = IEEE80211_M_IBSS; + /* + * Yech, slot time may change depending on the + * operating mode so reset it to be sure + * everything is setup appropriately. + */ + ieee80211_reset_erp(ic); + err = ENETRESET; + } + } else { + if (ic->ic_flags & IEEE80211_F_IBSSON) { + ic->ic_flags &= ~IEEE80211_F_IBSSON; + err = ENETRESET; + } + } + break; + default: + ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd); + outp->wldp_result = WL_NOTSUPPORTED; + err = EINVAL; + break; + } + + freemsg(*mp); + *mp = omp; + return (err); +} + +static int wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) { mblk_t *omp; @@ -682,6 +743,8 @@ if ((uint8_t *)conf > end) return; + conf->wl_ess_conf_length = sizeof (struct wl_ess_conf); + /* skip newly allocated NULL bss node */ if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr)) return; @@ -875,6 +938,8 @@ bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE); } ic->ic_curmode = IEEE80211_MODE_AUTO; + ic->ic_flags &= ~IEEE80211_F_IBSSON; + ic->ic_opmode = IEEE80211_M_STA; } static int @@ -1244,6 +1309,9 @@ case WL_BSS_TYPE: err = wifi_cfg_bsstype(ic, cmd, mp); break; + case WL_CREATE_IBSS: + err = wifi_cfg_createibss(ic, cmd, mp); + break; case WL_DESIRED_RATES: err = wifi_cfg_desrates(ic, cmd, mp); break; @@ -1492,11 +1560,9 @@ err = ENOTSUP; break; } - if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { - ic->ic_flags |= IEEE80211_F_IBSSON; - ic->ic_opmode = IEEE80211_M_IBSS; - err = ENETRESET; - } + + ic->ic_opmode = IEEE80211_M_IBSS; + err = ENETRESET; break; default: ieee80211_err("wl_set_bsstype: "
--- a/usr/src/uts/common/io/net80211/net80211_node.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/net80211/net80211_node.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,11 +1,11 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,8 +35,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Node management routines */ @@ -162,6 +160,7 @@ in->in_flags |= IEEE80211_NODE_AUTH; in->in_inact_reload = im->im_inact_run; + in->in_inact = in->in_inact_reload; } /* @@ -392,6 +391,9 @@ ieee80211_node_t *in; ieee80211_node_t *obss; + ieee80211_node_table_reset(&ic->ic_sta); + ieee80211_reset_erp(ic); + in = ieee80211_alloc_node(ic, &ic->ic_scan, ic->ic_macaddr); ASSERT(in != NULL); obss = ic->ic_bss;
--- a/usr/src/uts/common/io/net80211/net80211_output.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/net80211/net80211_output.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,11 +1,11 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +35,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma ident "%Z%%M% %I% %E% SMI" - - /* * Send out 802.11 frames */ @@ -402,18 +399,21 @@ if (mp == NULL) return (ENOMEM); - bzero(frm, 8); /* timestamp is set by hardware/driver */ + bzero(frm, 8); /* timestamp should be filled later */ frm += 8; - *(uint16_t *)frm = LE_16(in->in_intval); + *(uint16_t *)frm = LE_16(ic->ic_bss->in_intval); frm += 2; capinfo = ieee80211_get_capinfo(ic); *(uint16_t *)frm = LE_16(capinfo); frm += 2; - frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); + /* ssid */ + frm = ieee80211_add_ssid(frm, ic->ic_bss->in_essid, + ic->ic_bss->in_esslen); + /* supported rates */ frm = ieee80211_add_rates(frm, &in->in_rates); - if (ic->ic_phytype == IEEE80211_T_FH) { + if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) { *frm++ = IEEE80211_ELEMID_FHPARMS; *frm++ = IEEE80211_FH_LEN; *frm++ = in->in_fhdwell & 0x00ff; @@ -434,7 +434,12 @@ *frm++ = IEEE80211_IBSS_LEN; *frm++ = 0; *frm++ = 0; /* ATIM window */ } + /* ERP */ + if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) + frm = ieee80211_add_erp(frm, ic); + /* Extended supported rates */ frm = ieee80211_add_xrates(frm, &in->in_rates); + mp->b_wptr = frm; break; case IEEE80211_FC0_SUBTYPE_AUTH: @@ -593,6 +598,7 @@ frm = ieee80211_add_rates(frm, &in->in_rates); frm = ieee80211_add_xrates(frm, &in->in_rates); + mp->b_wptr = frm; break; case IEEE80211_FC0_SUBTYPE_DISASSOC:
--- a/usr/src/uts/common/io/net80211/net80211_proto.c Tue Jan 20 23:15:29 2009 -0800 +++ b/usr/src/uts/common/io/net80211/net80211_proto.c Wed Jan 21 16:12:41 2009 +0800 @@ -1,11 +1,11 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,8 +35,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * IEEE 802.11 protocol support */ @@ -106,49 +104,49 @@ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: (void) snprintf(buf2, sizeof (buf2), "NODS %s", - ieee80211_macaddr_sprintf(wh->i_addr2)); + ieee80211_macaddr_sprintf(wh->i_addr2)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "->%s", - ieee80211_macaddr_sprintf(wh->i_addr1)); + ieee80211_macaddr_sprintf(wh->i_addr1)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "(%s)", - ieee80211_macaddr_sprintf(wh->i_addr3)); + ieee80211_macaddr_sprintf(wh->i_addr3)); (void) strncat(buf1, buf2, sizeof (buf2)); break; case IEEE80211_FC1_DIR_TODS: (void) snprintf(buf2, sizeof (buf2), "TODS %s", - ieee80211_macaddr_sprintf(wh->i_addr2)); + ieee80211_macaddr_sprintf(wh->i_addr2)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "->%s", - ieee80211_macaddr_sprintf(wh->i_addr3)); + ieee80211_macaddr_sprintf(wh->i_addr3)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "(%s)", - ieee80211_macaddr_sprintf(wh->i_addr1)); + ieee80211_macaddr_sprintf(wh->i_addr1)); (void) strncat(buf1, buf2, sizeof (buf2)); break; case IEEE80211_FC1_DIR_FROMDS: (void) snprintf(buf2, sizeof (buf2), "FRDS %s", - ieee80211_macaddr_sprintf(wh->i_addr3)); + ieee80211_macaddr_sprintf(wh->i_addr3)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "->%s", - ieee80211_macaddr_sprintf(wh->i_addr1)); + ieee80211_macaddr_sprintf(wh->i_addr1)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "(%s)", - ieee80211_macaddr_sprintf(wh->i_addr2)); + ieee80211_macaddr_sprintf(wh->i_addr2)); (void) strncat(buf1, buf2, sizeof (buf2)); break; case IEEE80211_FC1_DIR_DSTODS: (void) snprintf(buf2, sizeof (buf2), "DSDS %s", - ieee80211_macaddr_sprintf((uint8_t *)&wh[1])); + ieee80211_macaddr_sprintf((uint8_t *)&wh[1])); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "->%s ", - ieee80211_macaddr_sprintf(wh->i_addr3)); + ieee80211_macaddr_sprintf(wh->i_addr3)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "%s", - ieee80211_macaddr_sprintf(wh->i_addr2)); + ieee80211_macaddr_sprintf(wh->i_addr2)); (void) strncat(buf1, buf2, sizeof (buf2)); (void) snprintf(buf2, sizeof (buf2), "->%s", - ieee80211_macaddr_sprintf(wh->i_addr1)); + ieee80211_macaddr_sprintf(wh->i_addr1)); (void) strncat(buf1, buf2, sizeof (buf2)); break; } @@ -161,13 +159,13 @@ break; case IEEE80211_FC0_TYPE_MGT: (void) snprintf(buf2, sizeof (buf2), "%s", - ieee80211_mgt_subtype_name[ - (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) - >> IEEE80211_FC0_SUBTYPE_SHIFT]); + ieee80211_mgt_subtype_name[ + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) + >> IEEE80211_FC0_SUBTYPE_SHIFT]); break; default: (void) snprintf(buf2, sizeof (buf2), "type#%d", - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); + wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); break; } (void) strncat(buf1, buf2, sizeof (buf2)); @@ -194,7 +192,7 @@ (void) strncat(buf1, buf2, 3); } ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", - buf1); + buf1); } } @@ -327,7 +325,7 @@ * the driver is capable of doing it. */ ieee80211_set_shortslottime(ic, - ic->ic_curmode == IEEE80211_MODE_11A); + ic->ic_curmode == IEEE80211_MODE_11A); /* * Set short preamble and ERP barker-preamble flags. */ @@ -424,7 +422,7 @@ if (ic->ic_flags & IEEE80211_F_SCAN) return; ieee80211_dbg(IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, - "%s\n", "beacon miss"); + "%s\n", "beacon miss"); /* * Our handling is only meaningful for stations that are @@ -446,9 +444,9 @@ */ IEEE80211_UNLOCK(ic); (void) ieee80211_send_probereq(ic->ic_bss, ic->ic_macaddr, - ic->ic_bss->in_bssid, ic->ic_bss->in_bssid, - ic->ic_bss->in_essid, ic->ic_bss->in_esslen, - ic->ic_opt_ie, ic->ic_opt_ie_len); + ic->ic_bss->in_bssid, ic->ic_bss->in_bssid, + ic->ic_bss->in_essid, ic->ic_bss->in_esslen, + ic->ic_opt_ie, ic->ic_opt_ie_len); return; } im->im_bmiss_count = 0; @@ -470,8 +468,8 @@ IEEE80211_LOCK(ic); ostate = ic->ic_state; ieee80211_dbg(IEEE80211_MSG_STATE, "ieee80211_newstate(): " - "%s -> %s\n", - ieee80211_state_name[ostate], ieee80211_state_name[nstate]); + "%s -> %s\n", + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); ic->ic_state = nstate; in = ic->ic_bss; im->im_swbmiss_period = 0; /* Reset software beacon miss period */ @@ -490,16 +488,23 @@ case IEEE80211_S_ASSOC: if (ic->ic_opmode == IEEE80211_M_STA) { IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_LEAVE); + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE); } break; case IEEE80211_S_RUN: - if (ic->ic_opmode == IEEE80211_M_STA) { + switch (ic->ic_opmode) { + case IEEE80211_M_STA: IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_DISASSOC, - IEEE80211_REASON_ASSOC_LEAVE); + IEEE80211_FC0_SUBTYPE_DISASSOC, + IEEE80211_REASON_ASSOC_LEAVE); ieee80211_sta_leave(ic, in); + break; + case IEEE80211_M_IBSS: + ieee80211_notify_node_leave(ic, in); + break; + default: + break; } break; } @@ -510,20 +515,9 @@ case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_INIT: - if (ic->ic_opmode == IEEE80211_M_IBSS && - ic->ic_des_chan != IEEE80211_CHAN_ANYC) { - /* - * AP operation and we already have a channel; - * bypass the scan and startup immediately. - */ - ieee80211_create_ibss(ic, ic->ic_des_chan); - } else { - IEEE80211_UNLOCK(ic); - ieee80211_begin_scan(ic, - (arg == 0) ? B_FALSE : B_TRUE); - return (0); - } - break; + IEEE80211_UNLOCK(ic); + ieee80211_begin_scan(ic, (arg == 0) ? B_FALSE : B_TRUE); + return (0); case IEEE80211_S_SCAN: /* * Scan next. If doing an active scan and the @@ -535,18 +529,18 @@ !IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) { IEEE80211_UNLOCK(ic); (void) ieee80211_send_probereq(in, - ic->ic_macaddr, wifi_bcastaddr, - wifi_bcastaddr, - ic->ic_des_essid, ic->ic_des_esslen, - ic->ic_opt_ie, ic->ic_opt_ie_len); + ic->ic_macaddr, wifi_bcastaddr, + wifi_bcastaddr, + ic->ic_des_essid, ic->ic_des_esslen, + ic->ic_opt_ie, ic->ic_opt_ie_len); return (0); } break; case IEEE80211_S_RUN: /* beacon miss */ ieee80211_dbg(IEEE80211_MSG_STATE, - "no recent beacons from %s, rescanning\n", - ieee80211_macaddr_sprintf(in->in_macaddr)); + "no recent beacons from %s, rescanning\n", + ieee80211_macaddr_sprintf(in->in_macaddr)); IEEE80211_UNLOCK(ic); ieee80211_sta_leave(ic, in); IEEE80211_LOCK(ic); @@ -556,7 +550,7 @@ case IEEE80211_S_ASSOC: /* timeout restart scan */ in = ieee80211_find_node(&ic->ic_scan, - ic->ic_bss->in_macaddr); + ic->ic_bss->in_macaddr); if (in != NULL) { in->in_fails++; ieee80211_unref_node(&in); @@ -565,12 +559,13 @@ } break; case IEEE80211_S_AUTH: + ASSERT(ic->ic_opmode == IEEE80211_M_STA); switch (ostate) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: IEEE80211_UNLOCK(ic); IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH, - 1); + 1); return (0); case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: @@ -578,7 +573,7 @@ case IEEE80211_FC0_SUBTYPE_AUTH: IEEE80211_UNLOCK(ic); IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_AUTH, 2); + IEEE80211_FC0_SUBTYPE_AUTH, 2); return (0); case IEEE80211_FC0_SUBTYPE_DEAUTH: /* ignore and retry scan on timeout */ @@ -591,37 +586,38 @@ ic->ic_state = ostate; /* stay RUN */ IEEE80211_UNLOCK(ic); IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_AUTH, 2); + IEEE80211_FC0_SUBTYPE_AUTH, 2); return (0); case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_UNLOCK(ic); ieee80211_sta_leave(ic, in); /* try to re-auth */ IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_AUTH, 1); + IEEE80211_FC0_SUBTYPE_AUTH, 1); return (0); } break; } break; case IEEE80211_S_ASSOC: + ASSERT(ic->ic_opmode == IEEE80211_M_STA); switch (ostate) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: case IEEE80211_S_ASSOC: ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_newstate: " - "invalid transition\n"); + "invalid transition\n"); break; case IEEE80211_S_AUTH: IEEE80211_UNLOCK(ic); IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); + IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); return (0); case IEEE80211_S_RUN: IEEE80211_UNLOCK(ic); ieee80211_sta_leave(ic, in); IEEE80211_SEND_MGMT(ic, in, - IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); + IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); return (0); } break; @@ -629,18 +625,17 @@ switch (ostate) { case IEEE80211_S_INIT: ieee80211_err("ieee80211_newstate: " - "invalid transition\n"); + "invalid transition\n"); break; case IEEE80211_S_AUTH: ieee80211_err("ieee80211_newstate: " - "invalid transition\n"); + "invalid transition\n"); break; case IEEE80211_S_SCAN: /* adhoc/hostap mode */ case IEEE80211_S_ASSOC: /* infra mode */ ASSERT(in->in_txrate < in->in_rates.ir_nrates); im->im_mgt_timer = 0; - if (ic->ic_opmode == IEEE80211_M_STA) - ieee80211_notify_node_join(ic, in); + ieee80211_notify_node_join(ic, in); /* * We can send data now; update the fastpath with our