/** * @brief This function implements command CMD_802_11D_DOMAIN_INFO * @param priv pointer to struct lbs_private * @param cmd pointer to cmd buffer * @param cmdno cmd ID * @param cmdOption cmd action * @return 0 */ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdoption) { struct cmd_ds_802_11d_domain_info *pdomaininfo = &cmd->params.domaininfo; struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; u8 nr_subband = priv->domainreg.nr_subband; lbs_deb_enter(LBS_DEB_11D); lbs_deb_11d("nr_subband=%x\n", nr_subband); cmd->command = cpu_to_le16(cmdno); pdomaininfo->action = cpu_to_le16(cmdoption); if (cmdoption == CMD_ACT_GET) { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); goto done; } domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); memcpy(domain->countrycode, priv->domainreg.countrycode, sizeof(domain->countrycode)); domain->header.len = cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + sizeof(domain->countrycode)); if (nr_subband) { memcpy(domain->subband, priv->domainreg.subband, nr_subband * sizeof(struct ieeetypes_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + le16_to_cpu(domain->header.len) + sizeof(struct mrvlietypesheader) + S_DS_GEN); } else { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); } lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); done: lbs_deb_enter(LBS_DEB_11D); return 0; }
static int wlan_ret_802_11_eeprom_access(wlan_private * priv, struct cmd_ds_command *resp) { wlan_adapter *adapter = priv->adapter; struct wlan_ioctl_regrdwr *pbuf; pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; lbs_deb_enter_args(LBS_DEB_CMD, "len %d", le16_to_cpu(resp->params.rdeeprom.bytecount)); if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { pbuf->NOB = 0; lbs_deb_cmd("EEPROM read length too big\n"); return -1; } pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); if (pbuf->NOB > 0) { memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } lbs_deb_leave(LBS_DEB_CMD); return 0; }
int lbs_cmd_bt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { struct cmd_ds_bt_access *bt_access = &cmd->params.bt; lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + sizeof(struct cmd_header)); cmd->result = 0; bt_access->action = cpu_to_le16(cmd_action); switch (cmd_action) { case CMD_ACT_BT_ACCESS_ADD: memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_DEL: memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_LIST: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; case CMD_ACT_BT_ACCESS_RESET: break; case CMD_ACT_BT_ACCESS_SET_INVERT: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; case CMD_ACT_BT_ACCESS_GET_INVERT: break; default: break; } lbs_deb_leave(LBS_DEB_CMD); return 0; }
/*********************************************************************************************** ****函数名:lbs_send_confirmsleep ****描述:网卡进入低功耗模式 ****参数:priv:全局驱动变量 ****返回:无 ***********************************************************************************************/ void lbs_send_confirmsleep(struct lbs_private *priv) { int ret; lbs_deb_enter(LBS_DEB_HOST); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep, sizeof(confirm_sleep)); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, sizeof(confirm_sleep)); if (ret) { lbs_pr_alert("confirm_sleep failed\n"); goto out; } /* We don't get a response on the sleep-confirmation */ priv->dnld_sent = DNLD_RES_RECEIVED; out: lbs_deb_leave(LBS_DEB_HOST); }
static int wlan_ret_802_11_data_rate(wlan_private * priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns * all data rates supported. */ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate); lbs_deb_leave(LBS_DEB_CMD); return 0; }
/** * @brief This function Checks if chan txpwr is learned from AP/IBSS * @param chan chan number * @param parsed_region_chan pointer to parsed_region_chan_11d * @return TRUE; FALSE */ static u8 wlan_channel_known_11d(u8 chan, struct parsed_region_chan_11d * parsed_region_chan) { struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; u8 nr_chan = parsed_region_chan->nr_chan; u8 i = 0; lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr, sizeof(struct chan_power_11d) * nr_chan); for (i = 0; i < nr_chan; i++) { if (chan == chanpwr[i].chan) { lbs_deb_11d("found chan %d\n", chan); return 1; } } lbs_deb_11d("chan %d not found\n", chan); return 0; }
static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) { unsigned long flags; wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n", size); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->intcounter || adapter->currenttxskb) lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", adapter->intcounter, adapter->currenttxskb); spin_unlock_irqrestore(&adapter->driver_lock, flags); if (ret) { lbs_pr_alert( "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); } else { spin_lock_irqsave(&adapter->driver_lock, flags); if (!adapter->intcounter) { adapter->psstate = PS_STATE_SLEEP; } else { lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
/** * @brief This function parses countryinfo from AP and download country info to FW * @param priv pointer to wlan_private * @param resp pointer to command response buffer * @return 0; -1 */ int libertas_ret_802_11d_domain_info(wlan_private * priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; struct mrvlietypes_domainparamset *domain = &domaininfo->domain; u16 action = le16_to_cpu(domaininfo->action); s16 ret = 0; u8 nr_subband = 0; lbs_deb_enter(LBS_DEB_11D); lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / sizeof(struct ieeetypes_subbandset); lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { lbs_deb_11d("Invalid Numrer of Subband returned!!\n"); return -1; } switch (action) { case CMD_ACT_SET: /*Proc Set action */ break; case CMD_ACT_GET: break; default: lbs_deb_11d("Invalid action:%d\n", domaininfo->action); ret = -1; break; } lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); return ret; }
static int lbs_send_confirmwake(struct lbs_private *priv) { struct cmd_header cmd; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); cmd.size = cpu_to_le16(sizeof(cmd)); cmd.seqnum = cpu_to_le16(++priv->seqnum); cmd.result = 0; lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd, sizeof(cmd)); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd)); if (ret) lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n"); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
static int wlan_cmd_802_11_mac_address(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmd_action) { wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + S_DS_GEN); cmd->result = 0; cmd->params.macadd.action = cpu_to_le16(cmd_action); if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, adapter->current_addr, ETH_ALEN); lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); } lbs_deb_leave(LBS_DEB_CMD); return 0; }
/** * @brief This function processes received packet and forwards it * to kernel/upper layer * * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { int ret = 0; struct net_device *dev = priv->dev; struct rxpackethdr *p_rx_pkt; struct rxpd *p_rx_pd; int hdrchop; struct ethhdr *p_ethhdr; const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; lbs_deb_enter(LBS_DEB_RX); BUG_ON(!skb); skb->ip_summed = CHECKSUM_NONE; if (priv->monitormode) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; p_rx_pd = &p_rx_pkt->rx_pd; if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) dev = priv->mesh_dev; lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received with bad length\n"); dev->stats.rx_length_errors++; ret = 0; dev_kfree_skb(skb); goto done; } /* * Check rxpd status and update 802.3 stat, */ if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { lbs_deb_rx("rx err: frame received with bad status\n"); lbs_pr_alert("rxpd not ok\n"); dev->stats.rx_errors++; ret = 0; dev_kfree_skb(skb); goto done; } lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); if (memcmp(&p_rx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type (ethertype) * * The firmware only passes up SNAP frames converting * all RX Data from 802.11 to 802.2/LLC/SNAP frames. * * To create the Ethernet II, just move the src, dst address right * before the snap_type. */ p_ethhdr = (struct ethhdr *) ((u8 *) & p_rx_pkt->eth803_hdr + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) - sizeof(p_rx_pkt->eth803_hdr.dest_addr) - sizeof(p_rx_pkt->eth803_hdr.src_addr) - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, sizeof(p_ethhdr->h_source)); memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_ethhdr->h_dest)); /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; } else { lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; } /* Chop off the leading header bytes so the skb points to the start of * either the reconstructed EthII frame or the 802.2/llc/snap frame */ skb_pull(skb, hdrchop); /* Take the data rate from the rxpd structure * only if the rate is auto */ if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); lbs_compute_rssi(priv, p_rx_pd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; skb->protocol = eth_type_trans(skb, dev); if (in_interrupt()) netif_rx(skb); else netif_rx_ni(skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; }
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) { uint16_t respcmd, curcmd; struct cmd_header *resp; int ret = 0; unsigned long flags; uint16_t result; lbs_deb_enter(LBS_DEB_HOST); mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); if (!priv->cur_cmd) { lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; spin_unlock_irqrestore(&priv->driver_lock, flags); goto done; } resp = (void *)data; curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n", respcmd, le16_to_cpu(resp->seqnum), len); lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (respcmd != CMD_RET(curcmd) && respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (resp->result == cpu_to_le16(0x0004)) { /* 0x0004 means -EAGAIN. Drop the response, let it time out and be resubmitted */ lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", le16_to_cpu(resp->command)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } /* Now we got response from FW, cancel the command timer */ del_timer(&priv->command_timer); priv->cmd_timed_out = 0; if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1]; u16 action = le16_to_cpu(psmode->action); lbs_deb_host( "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", result, action); if (result) { lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", result); /* * We should not re-try enter-ps command in * ad-hoc mode. It takes place in * lbs_execute_next_command(). */ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR && action == PS_MODE_ACTION_ENTER_PS) priv->psmode = LBS802_11POWERMODECAM; } else if (action == PS_MODE_ACTION_ENTER_PS) { priv->needtowakeup = 0; priv->psstate = PS_STATE_AWAKE; lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); if (priv->connect_status != LBS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. */ lbs_deb_host( "disconnected, invoking lbs_ps_wakeup\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); mutex_unlock(&priv->lock); lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false); mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); } } else if (action == PS_MODE_ACTION_EXIT_PS) { priv->needtowakeup = 0; priv->psstate = PS_STATE_FULL_POWER; lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } lbs_complete_command(priv, priv->cur_cmd, result); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = 0; goto done; } /* If the command is not successful, cleanup and return failure */ if ((result != 0 || !(respcmd & 0x8000))) { lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", result, respcmd); /* * Handling errors here */ switch (respcmd) { case CMD_RET(CMD_GET_HW_SPEC): case CMD_RET(CMD_802_11_RESET): lbs_deb_host("CMD_RESP: reset failed\n"); break; } lbs_complete_command(priv, priv->cur_cmd, result); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } spin_unlock_irqrestore(&priv->driver_lock, flags); if (priv->cur_cmd && priv->cur_cmd->callback) { ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, resp); } spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { /* Clean up and Put current command back to cmdfreeq */ lbs_complete_command(priv, priv->cur_cmd, result); } spin_unlock_irqrestore(&priv->driver_lock, flags); done: mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
/** * @brief This function checks if chan txpwr is learned from AP/IBSS * @param chan chan number * @param parsed_region_chan pointer to parsed_region_chan_11d * @return 0 */ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* countryinfo, u8 band, struct parsed_region_chan_11d * parsed_region_chan) { u8 nr_subband, nrchan; u8 lastchan, firstchan; u8 region; u8 curchan = 0; u8 idx = 0; /*chan index in parsed_region_chan */ u8 j, i; lbs_deb_enter(LBS_DEB_11D); /*validation Rules: 1. valid region Code 2. First Chan increment 3. channel range no overlap 4. channel is valid? 5. channel is supported by region? 6. Others */ lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 || (countryinfo->len <= COUNTRY_CODE_LEN)) { /* No region Info or Wrong region info: treat as No 11D info */ goto done; } /*Step1: check region_code */ parsed_region_chan->region = region = wlan_region_2_code(countryinfo->countrycode); lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, COUNTRY_CODE_LEN); parsed_region_chan->band = band; memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, COUNTRY_CODE_LEN); nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / sizeof(struct ieeetypes_subbandset); for (j = 0, lastchan = 0; j < nr_subband; j++) { if (countryinfo->subband[j].firstchan <= lastchan) { /*Step2&3. Check First Chan Num increment and no overlap */ lbs_deb_11d("chan %d>%d, overlap\n", countryinfo->subband[j].firstchan, lastchan); continue; } firstchan = countryinfo->subband[j].firstchan; nrchan = countryinfo->subband[j].nrchan; for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { /*step4: channel is supported? */ if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { /* Chan is not found in UN table */ lbs_deb_11d("chan is not supported: %d \n", i); break; } lastchan = curchan; if (wlan_region_chan_supported_11d (region, band, curchan)) { /*step5: Check if curchan is supported by mrvl in region */ parsed_region_chan->chanpwr[idx].chan = curchan; parsed_region_chan->chanpwr[idx].pwr = countryinfo->subband[j].maxtxpwr; idx++; } else { /*not supported and ignore the chan */ lbs_deb_11d( "i %d, chan %d unsupported in region %x, band %d\n", i, curchan, region, band); } } /*Step6: Add other checking if any */ } parsed_region_chan->nr_chan = idx; lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan); lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan, 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); done: lbs_deb_enter(LBS_DEB_11D); return 0; }
/** * lbs_hard_start_xmit - checks the conditions and sends packet to IF * layer if everything is ok * * @skb: A pointer to skb which includes TX packet * @dev: A pointer to the &struct net_device * returns: 0 or -1 */ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; struct lbs_private *priv = dev->ml_priv; struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; netdev_tx_t ret = NETDEV_TX_OK; lbs_deb_enter(LBS_DEB_TX); /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); if (priv->surpriseremoved) goto free; if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); /* We'll never manage to send this one; drop it and return 'OK' */ dev->stats.tx_dropped++; dev->stats.tx_errors++; goto free; } netif_stop_queue(priv->dev); if (priv->mesh_dev) netif_stop_queue(priv->mesh_dev); if (priv->tx_pending_len) { /* This can happen if packets come in on the mesh and eth device simultaneously -- there's no mutual exclusion on hard_start_xmit() calls between devices. */ lbs_deb_tx("Packet on %s while busy\n", dev->name); ret = NETDEV_TX_BUSY; goto unlock; } priv->tx_pending_len = -1; spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); txpd = (void *)priv->tx_pending_buf; memset(txpd, 0, sizeof(struct txpd)); p802x_hdr = skb->data; pkt_len = skb->len; if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; /* set txpd fields from the radiotap header */ txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate)); /* skip the radiotap header */ p802x_hdr += sizeof(*rtap_hdr); pkt_len -= sizeof(*rtap_hdr); /* copy destination address from 802.11 header */ memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); } else { /* copy destination address from 802.3 header */ memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); } txpd->tx_packet_length = cpu_to_le16(pkt_len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); lbs_mesh_set_txpd(priv, dev, txpd); lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); spin_lock_irqsave(&priv->driver_lock, flags); priv->tx_pending_len = pkt_len + sizeof(struct txpd); lbs_deb_tx("%s lined up packet\n", __func__); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); /* Keep the skb around for when we get feedback */ priv->currenttxskb = skb; } else { free: dev_kfree_skb_any(skb); } unlock: spin_unlock_irqrestore(&priv->driver_lock, flags); wake_up(&priv->waitq); lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); return ret; }
int libertas_process_rx_command(wlan_private * priv) { u16 respcmd; struct cmd_ds_command *resp; wlan_adapter *adapter = priv->adapter; int ret = 0; ulong flags; u16 result; lbs_deb_enter(LBS_DEB_HOST); /* Now we got response from FW, cancel the command timer */ del_timer(&adapter->command_timer); mutex_lock(&adapter->lock); spin_lock_irqsave(&adapter->driver_lock, flags); if (!adapter->cur_cmd) { lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; } resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", respcmd, priv->upld_len, jiffies); lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, priv->upld_len); if (!(respcmd & 0x8000)) { lbs_deb_host("invalid response!\n"); adapter->cur_cmd_retcode = -1; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; goto done; } /* Store the response code to cur_cmd_retcode. */ adapter->cur_cmd_retcode = result;; if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); lbs_deb_host( "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", result, action); if (result) { lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", result); /* * We should not re-try enter-ps command in * ad-hoc mode. It takes place in * libertas_execute_next_command(). */ if (adapter->mode == IW_MODE_ADHOC && action == CMD_SUBCMD_ENTER_PS) adapter->psmode = WLAN802_11POWERMODECAM; } else if (action == CMD_SUBCMD_ENTER_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_AWAKE; lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); if (adapter->connect_status != LIBERTAS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. */ lbs_deb_host( "disconnected, invoking libertas_ps_wakeup\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); mutex_unlock(&adapter->lock); libertas_ps_wakeup(priv, 0); mutex_lock(&adapter->lock); spin_lock_irqsave(&adapter->driver_lock, flags); } } else if (action == CMD_SUBCMD_EXIT_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_FULL_POWER; lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = 0; goto done; } if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { /* Copy the response back to response buffer */ memcpy(adapter->cur_cmd->pdata_buf, resp, le16_to_cpu(resp->size)); adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; } /* If the command is not successful, cleanup and return failure */ if ((result != 0 || !(respcmd & 0x8000))) { lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", result, respcmd); /* * Handling errors here */ switch (respcmd) { case CMD_RET(CMD_GET_HW_SPEC): case CMD_RET(CMD_802_11_RESET): lbs_deb_host("CMD_RESP: reset failed\n"); break; } __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; goto done; } spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = handle_cmd_response(respcmd, resp, priv); spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { /* Clean up and Put current command back to cmdfreeq */ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; WARN_ON(adapter->nr_cmd_pending > 128); adapter->cur_cmd = NULL; } spin_unlock_irqrestore(&adapter->driver_lock, flags); done: mutex_unlock(&adapter->lock); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
/** * @brief This function processes received packet and forwards it * to kernel/upper layer * * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, char *buffer,u16 size) { int ret = 0; struct rxpackethdr *p_rx_pkt; struct rxpd *p_rx_pd; int hdrchop; struct ethhdr *p_ethhdr; const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct eth_packet *rx_ethpkt = &priv->rx_pkt; lbs_deb_enter(LBS_DEB_RX); p_rx_pd = (struct rxpd *)buffer; p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd + le32_to_cpu(p_rx_pd->pkt_ptr)); if (size < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received with bad length\n"); ret = 0; goto done; } #ifdef MASK_DEBUG lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n", size, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr), size - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); #endif if (memcmp(&p_rx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type (ethertype) * * The firmware only passes up SNAP frames converting * all RX Data from 802.11 to 802.2/LLC/SNAP frames. * * To create the Ethernet II, just move the src, dst address right * before the snap_type. */ p_ethhdr = (struct ethhdr *) ((u8 *) & p_rx_pkt->eth803_hdr + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) - sizeof(p_rx_pkt->eth803_hdr.dest_addr) - sizeof(p_rx_pkt->eth803_hdr.src_addr) - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, sizeof(p_ethhdr->h_source)); memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_ethhdr->h_dest)); /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd; } else{ lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd; } /* Chop off the leading header bytes so the skb points to the start of * either the reconstructed EthII frame or the 802.2/llc/snap frame */ //skb_pull(skb, hdrchop); rx_ethpkt->len = size - hdrchop; rx_ethpkt->data = (char *)((char *)buffer+hdrchop); //Delivery the data into HelloX's kernel. //DeliveryPacket(rx_ethpkt->data,rx_ethpkt->len,NULL); #if 0 if (priv->enablehwauto) { priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); } lbs_compute_rssi(priv, p_rx_pd); #endif ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, ret); return ret; }
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) { uint16_t respcmd, curcmd; struct cmd_header *resp; int ret = 0; unsigned long flags; uint16_t result; lbs_deb_enter(LBS_DEB_HOST); mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); if (!priv->cur_cmd) { lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; spin_unlock_irqrestore(&priv->driver_lock, flags); goto done; } resp = (void *)data; curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n", respcmd, le16_to_cpu(resp->seqnum), len); lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { netdev_info(priv->dev, "Received CMD_RESP with invalid sequence %d (expected %d)\n", le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (respcmd != CMD_RET(curcmd) && respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (resp->result == cpu_to_le16(0x0004)) { /* */ netdev_info(priv->dev, "Firmware returns DEFER to command %x. Will let it time out...\n", le16_to_cpu(resp->command)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } /* */ del_timer(&priv->command_timer); priv->cmd_timed_out = 0; if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1]; u16 action = le16_to_cpu(psmode->action); lbs_deb_host( "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", result, action); if (result) { lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", result); /* */ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR && action == PS_MODE_ACTION_ENTER_PS) priv->psmode = LBS802_11POWERMODECAM; } else if (action == PS_MODE_ACTION_ENTER_PS) { priv->needtowakeup = 0; priv->psstate = PS_STATE_AWAKE; lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); if (priv->connect_status != LBS_CONNECTED) { /* */ lbs_deb_host( "disconnected, invoking lbs_ps_wakeup\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); mutex_unlock(&priv->lock); lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false); mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); } } else if (action == PS_MODE_ACTION_EXIT_PS) { priv->needtowakeup = 0; priv->psstate = PS_STATE_FULL_POWER; lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } __lbs_complete_command(priv, priv->cur_cmd, result); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = 0; goto done; } /* */ if ((result != 0 || !(respcmd & 0x8000))) { lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", result, respcmd); /* */ switch (respcmd) { case CMD_RET(CMD_GET_HW_SPEC): case CMD_RET(CMD_802_11_RESET): lbs_deb_host("CMD_RESP: reset failed\n"); break; } __lbs_complete_command(priv, priv->cur_cmd, result); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } spin_unlock_irqrestore(&priv->driver_lock, flags); if (priv->cur_cmd && priv->cur_cmd->callback) { ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, resp); } spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { /* */ __lbs_complete_command(priv, priv->cur_cmd, result); } spin_unlock_irqrestore(&priv->driver_lock, flags); done: mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
/** * @brief This function processes received packet and forwards it * to kernel/upper layer * * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, char *buffer,u16 size) { int ret = 0; struct rxpackethdr *p_rx_pkt; struct rxpd *p_rx_pd; int hdrchop; struct ethhdr *p_ethhdr; const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct eth_packet *rx_ethpkt=&priv->rx_pkt;//我们要的以太网数据报 lbs_deb_enter(LBS_DEB_RX); p_rx_pd = (struct rxpd *)buffer;//包的状态信息 p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd + le32_to_cpu(p_rx_pd->pkt_ptr));//得到存放802.3的头信息的地址 // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", buffer, // min(size, 100)); if (size < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received with bad length\n"); ret = 0; goto done; } #ifdef MASK_DEBUG lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n", size, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr), size - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); #endif if (memcmp(&p_rx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {//这是RFC1042中定义的SNAP头信息,比较是否是rfc1042封装的mac帧 /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type (ethertype) * * The firmware only passes up SNAP frames converting * all RX Data from 802.11 to 802.2/LLC/SNAP frames. * * To create the Ethernet II, just move the src, dst address right * before the snap_type. */ //marvel芯片给出的数据为802.11LLC层的数据包格式,有snap头,现在将其更改为802.3的 //数据报格式,只要将802.11mac头信息中的源地址和目的地址复制到snap的右边即可,具体格式请参考相关标准的 //mac帧格式 p_ethhdr = (struct ethhdr *) ((u8 *) & p_rx_pkt->eth803_hdr + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) - sizeof(p_rx_pkt->eth803_hdr.dest_addr) - sizeof(p_rx_pkt->eth803_hdr.src_addr) - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));//找出存放802.3 MAC的起始位置 memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,//直接覆盖,从后往前拷贝 sizeof(p_ethhdr->h_source)); memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_ethhdr->h_dest)); /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd;//用于重新更改skb->data的地址,后面使用的是skb_pull } else { lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd; } /* Chop off the leading header bytes so the skb points to the start of * either the reconstructed EthII frame or the 802.2/llc/snap frame */ //skb_pull(skb, hdrchop);//去掉前面的rxtp以及802.11mac rx_ethpkt->len=size-hdrchop; rx_ethpkt->data=(char *)((char *)buffer+hdrchop);//这就是我们数据的真正存放地址 //dbg_netdata("rx network data",rx_ethpkt->data,rx_ethpkt->len); /* Take the data rate from the rxpd structure * only if the rate is auto */ #if 0 if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);//记录下当前数据传输的速率 lbs_compute_rssi(priv, p_rx_pd);//副产品,计算RSSI信号强度 #endif ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, ret); return ret; }
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; struct lbs_private *priv = dev->priv; struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; int ret; lbs_deb_enter(LBS_DEB_TX); #if (ANDROID_POWER_SAVE == 1) if (priv->deepsleep == false) lbs_update_ps_timer(); else { if (priv->wifi_ps_work_req == 0) { printk("Need to wakeup for xmit: ether_proto=%x.\n", skb->protocol); priv->wifi_ps_work_req = WIFI_PS_PRE_WAKE; /* * If no netif_carrier_off, upper layer will try again, * and this may cause tx timeout and trigger watchdog. */ netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); queue_delayed_work(priv->work_thread, &priv->ps_work, msecs_to_jiffies(5)); } return NETDEV_TX_BUSY; } #endif ret = NETDEV_TX_OK; /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); if (priv->surpriseremoved) goto free; if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); /* We'll never manage to send this one; drop it and return 'OK' */ dev->stats.tx_dropped++; dev->stats.tx_errors++; goto free; } netif_stop_queue(priv->dev); if (priv->tx_pending_len) { /* This can happen if packets come in on the mesh and eth device simultaneously -- there's no mutual exclusion on hard_start_xmit() calls between devices. */ lbs_deb_tx("Packet on %s while busy\n", dev->name); ret = NETDEV_TX_BUSY; goto unlock; } priv->tx_pending_len = -1; spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); txpd = (void *)priv->tx_pending_buf; memset(txpd, 0, sizeof(struct txpd)); p802x_hdr = skb->data; pkt_len = skb->len; /* copy destination address from 802.3 header */ memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); txpd->tx_packet_length = cpu_to_le16(pkt_len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); spin_lock_irqsave(&priv->driver_lock, flags); priv->tx_pending_len = pkt_len + sizeof(struct txpd); lbs_deb_tx("%s lined up packet\n", __func__); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; if (priv->monitormode) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); /* Keep the skb around for when we get feedback */ priv->currenttxskb = skb; } else { free: dev_kfree_skb_any(skb); } unlock: spin_unlock_irqrestore(&priv->driver_lock, flags); wake_up(&priv->waitq); lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); return ret; }
/* * TODO: Fix the issue when DownloadcommandToStation is being called the * second time when the command times out. All the cmdptr->xxx are in little * endian and therefore all the comparissions will fail. * For now - we are not performing the endian conversion the second time - but * for PS and DEEP_SLEEP we need to worry */ static int DownloadcommandToStation(wlan_private * priv, struct cmd_ctrl_node *cmdnode) { unsigned long flags; struct cmd_ds_command *cmdptr; wlan_adapter *adapter = priv->adapter; int ret = -1; u16 cmdsize; u16 command; lbs_deb_enter(LBS_DEB_HOST); if (!adapter || !cmdnode) { lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); goto done; } cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; spin_lock_irqsave(&adapter->driver_lock, flags); if (!cmdptr || !cmdptr->size) { lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); __libertas_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; } adapter->cur_cmd = cmdnode; adapter->cur_cmd_retcode = 0; spin_unlock_irqrestore(&adapter->driver_lock, flags); cmdsize = cmdptr->size; command = cpu_to_le16(cmdptr->command); lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", command, le16_to_cpu(cmdptr->size), jiffies); lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize); cmdnode->cmdwaitqwoken = 0; cmdsize = cpu_to_le16(cmdsize); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); if (ret != 0) { lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); spin_lock_irqsave(&adapter->driver_lock, flags); adapter->cur_cmd_retcode = ret; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; } lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies); /* Setup the timer after transmit command */ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE || command == CMD_802_11_ASSOCIATE) mod_timer(&adapter->command_timer, jiffies + (10*HZ)); else mod_timer(&adapter->command_timer, jiffies + (5*HZ)); ret = 0; done: lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }