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; }
/** * lbs_add_mesh - add mshX interface * * @priv: A pointer to the &struct lbs_private structure * returns: 0 if successful, -X otherwise */ static int lbs_add_mesh(struct lbs_private *priv) { struct net_device *mesh_dev = NULL; struct wireless_dev *mesh_wdev; int ret = 0; lbs_deb_enter(LBS_DEB_MESH); /* Allocate a virtual mesh device */ mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!mesh_wdev) { lbs_deb_mesh("init mshX wireless device failed\n"); ret = -ENOMEM; goto done; } mesh_dev = alloc_netdev(0, "msh%d", ether_setup); if (!mesh_dev) { lbs_deb_mesh("init mshX device failed\n"); ret = -ENOMEM; goto err_free_wdev; } mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT; mesh_wdev->wiphy = priv->wdev->wiphy; mesh_wdev->netdev = mesh_dev; mesh_dev->ml_priv = priv; mesh_dev->ieee80211_ptr = mesh_wdev; priv->mesh_dev = mesh_dev; mesh_dev->netdev_ops = &mesh_netdev_ops; mesh_dev->ethtool_ops = &lbs_ethtool_ops; memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN); SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { pr_err("cannot register mshX virtual interface\n"); goto err_free_netdev; } ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); if (ret) goto err_unregister; lbs_persist_config_init(mesh_dev); /* Everything successful */ ret = 0; goto done; err_unregister: unregister_netdev(mesh_dev); err_free_netdev: free_netdev(mesh_dev); err_free_wdev: kfree(mesh_wdev); done: lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; }
/** * lbs_add_card - adds the card. It will probe the * card, allocate the lbs_priv and initialize the device. * * @card: A pointer to card * @dmdev: A pointer to &struct device * returns: A pointer to &struct lbs_private structure */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { struct net_device *dev; struct wireless_dev *wdev; struct lbs_private *priv = NULL; lbs_deb_enter(LBS_DEB_MAIN); /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { pr_err("cfg80211 init failed\n"); goto done; } wdev->iftype = NL80211_IFTYPE_STATION; priv = wdev_priv(wdev); priv->wdev = wdev; if (lbs_init_adapter(priv)) { pr_err("failed to initialize adapter structure\n"); goto err_wdev; } dev = alloc_netdev(0, "wlan%d", ether_setup); if (!dev) { dev_err(dmdev, "no memory for network device instance\n"); goto err_adapter; } dev->ieee80211_ptr = wdev; dev->ml_priv = priv; SET_NETDEV_DEV(dev, dmdev); wdev->netdev = dev; priv->dev = dev; dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &lbs_ethtool_ops; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; priv->card = card; strcpy(dev->name, "wlan%d"); lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); goto err_ndev; } priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); priv->wol_criteria = EHS_REMOVE_WAKEUP; priv->wol_gpio = 0xff; priv->wol_gap = 20; priv->ehs_remove_supported = true; goto done; err_ndev: free_netdev(dev); err_adapter: lbs_free_adapter(priv); err_wdev: lbs_cfg_free(priv); priv = NULL; done: lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv); return priv; }
static int lbs_init_adapter(struct lbs_private *priv) { size_t bufsize; int i, ret = 0; static u8 gnet_bss_desc[MAX_NETWORK_COUNT * sizeof(struct bss_descriptor)]; lbs_deb_enter("enter lbs_init_adapter\n"); /* Allocate buffer to store the BSSID list */ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); /*priv->networks = kzalloc(bufsize, GFP_KERNEL); if (!priv->networks) { lbs_pr_err("Out of memory allocating beacons\n"); ret = -1; goto out; }*/ priv->networks=(struct bss_descriptor *)gnet_bss_desc; memset(priv->networks,0,bufsize); /* Initialize scan result lists */ INIT_LIST_HEAD(&priv->network_free_list);//Initialize scan related list and objects. INIT_LIST_HEAD(&priv->network_list); //Link all bss descriptors into free list. for (i = 0; i < MAX_NETWORK_COUNT; i++) { list_add_tail(&priv->networks[i].list, &priv->network_free_list); } memset(priv->current_addr, 0xff, ETH_ALEN); priv->connect_status = LBS_DISCONNECTED; priv->mesh_connect_status = LBS_DISCONNECTED; priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radio_on = 1; priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; //mutex_init(&priv->lock); /*setup_timer(&priv->command_timer, command_timer_fn, (unsigned long)priv);*/ INIT_LIST_HEAD(&priv->cmdfreeq); INIT_LIST_HEAD(&priv->cmdpendingq); /*spin_lock_init(&priv->driver_lock); init_waitqueue_head(&priv->cmd_pending);*/ /* Allocate the command buffers */ if (lbs_allocate_cmd_buffer(priv)) { lbs_pr_err("Out of memory allocating command buffers\n"); ret = -ENOMEM; goto out; } priv->resp_idx = 0; priv->resp_len[0] = 0; //Contains the response from hardware. /* Create the event FIFO */ /*priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL); if (IS_ERR(priv->event_fifo)) { lbs_pr_err("Out of memory allocating event FIFO buffer\n"); ret = -ENOMEM; goto out; }*/ out: lbs_deb_leave_args("leave lbs_init_adapter(ret=%d)\n", ret); return ret; }
int lbs_process_event(struct lbs_private *priv, u32 event) { int ret = 0; lbs_deb_enter(LBS_DEB_CMD); switch (event) { case MACREG_INT_CODE_LINK_SENSED: printk("EVENT: link sensed\n");//掉线 break; case MACREG_INT_CODE_DEAUTHENTICATED: printk("EVENT: deauthenticated\n"); //lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: printk("EVENT: disassociated\n"); //lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOST_NO_SCAN: printk("EVENT: link lost\n"); //lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: printk("EVENT: ps sleep\n"); /* handle unexpected PS SLEEP event */ if (priv->psstate == PS_STATE_FULL_POWER) { printk("EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } priv->psstate = PS_STATE_PRE_SLEEP; //lbs_ps_confirm_sleep(priv); break; case MACREG_INT_CODE_HOST_AWAKE: printk("EVENT: host awake\n"); //lbs_send_confirmwake(priv); break; case MACREG_INT_CODE_PS_AWAKE: printk("EVENT: ps awake\n"); /* handle unexpected PS AWAKE event */ if (priv->psstate == PS_STATE_FULL_POWER) { printk( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } priv->psstate = PS_STATE_AWAKE; if (priv->needtowakeup) { /* * wait for the command processing to finish * before resuming sending * priv->needtowakeup will be set to FALSE * in lbs_ps_wakeup() */ printk("waking up ...\n"); //lbs_ps_wakeup(priv, 0); } break; case MACREG_INT_CODE_MIC_ERR_UNICAST: printk("EVENT: UNICAST MIC ERROR\n"); //handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: printk("EVENT: MULTICAST MIC ERROR\n"); //handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); break; case MACREG_INT_CODE_MIB_CHANGED: printk("EVENT: MIB CHANGED\n"); break; case MACREG_INT_CODE_INIT_DONE: printk("EVENT: INIT DONE\n"); break; case MACREG_INT_CODE_ADHOC_BCN_LOST: printk("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: printk("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: printk("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: printk("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: printk("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: printk("EVENT: snr high\n"); break; #ifdef MASK_DEBUG case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events if autostart is disabled */ if (!priv->mesh_autostart_enabled) { lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); priv->mesh_connect_status = LBS_CONNECTED; if (priv->mesh_open) { netif_carrier_on(priv->mesh_dev); if (!priv->tx_pending_len) netif_wake_queue(priv->mesh_dev); } priv->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; #endif default: printk("EVENT: unknown event id %d\n", event); break; } lbs_deb_leave_args(LBS_DEB_CMD, ret); return ret; }
int libertas_process_event(wlan_private * priv) { int ret = 0; wlan_adapter *adapter = priv->adapter; u32 eventcause; lbs_deb_enter(LBS_DEB_CMD); spin_lock_irq(&adapter->driver_lock); eventcause = adapter->eventcause; spin_unlock_irq(&adapter->driver_lock); lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: lbs_deb_cmd("EVENT: deauthenticated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: lbs_deb_cmd("EVENT: disassociated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: lbs_deb_cmd("EVENT: link lost\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: lbs_deb_cmd("EVENT: sleep\n"); /* handle unexpected PS SLEEP event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } adapter->psstate = PS_STATE_PRE_SLEEP; libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); break; case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: awake\n"); /* handle unexpected PS AWAKE event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } adapter->psstate = PS_STATE_AWAKE; if (adapter->needtowakeup) { /* * wait for the command processing to finish * before resuming sending * adapter->needtowakeup will be set to FALSE * in libertas_ps_wakeup() */ lbs_deb_cmd("waking up ...\n"); libertas_ps_wakeup(priv, 0); } break; case MACREG_INT_CODE_MIC_ERR_UNICAST: lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); break; case MACREG_INT_CODE_MIB_CHANGED: case MACREG_INT_CODE_INIT_DONE: break; case MACREG_INT_CODE_ADHOC_BCN_LOST: lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: lbs_pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: lbs_pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: lbs_pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: lbs_pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: lbs_pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events if autostart is disabled */ if (!priv->mesh_autostart_enabled) { lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev); netif_carrier_on(priv->mesh_dev); } adapter->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; default: lbs_pr_alert("EVENT: unknown event id 0x%04x\n", eventcause >> SBI_EVENT_CAUSE_SHIFT); break; } spin_lock_irq(&adapter->driver_lock); adapter->eventcause = 0; spin_unlock_irq(&adapter->driver_lock); lbs_deb_leave_args(LBS_DEB_CMD, "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; }
/** * @brief This function processes received packet and forwards it * to kernel/upper layer * * @param priv A pointer to wlan_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) { wlan_adapter *adapter = priv->adapter; 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 }; lbs_deb_enter(LBS_DEB_RX); if (priv->adapter->monitormode != WLAN_MONITOR_OFF) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; p_rx_pd = &p_rx_pkt->rx_pd; if (p_rx_pd->rx_control & RxPD_MESH_FRAME) SET_MESH_FRAME(skb); else UNSET_MESH_FRAME(skb); 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"); priv->stats.rx_length_errors++; ret = 0; 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"); priv->stats.rx_errors++; ret = 0; 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 (adapter->auto_rate) adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate); wlan_compute_rssi(priv, p_rx_pd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; libertas_upload_rx_packet(priv, skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; }
/** * @brief This function processes a received 802.11 packet and forwards it * to kernel/upper layer * * @param priv A pointer to wlan_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) { wlan_adapter *adapter = priv->adapter; int ret = 0; struct rx80211packethdr *p_rx_pkt; struct rxpd *prxpd; struct rx_radiotap_hdr radiotap_hdr; struct rx_radiotap_hdr *pradiotap_hdr; lbs_deb_enter(LBS_DEB_RX); p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received wit bad length\n"); priv->stats.rx_length_errors++; ret = 0; goto done; } /* * Check rxpd status and update 802.3 stat, */ if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { //lbs_deb_rx("rx err: frame received with bad status\n"); priv->stats.rx_errors++; } lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ if(priv->adapter->monitormode == WLAN_MONITOR_OFF) { /* no radio header */ /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); } else { /* radiotap header */ radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ radiotap_hdr.hdr.it_pad = 0; radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); /* unknown values */ radiotap_hdr.flags = 0; radiotap_hdr.chan_freq = 0; radiotap_hdr.chan_flags = 0; radiotap_hdr.antenna = 0; /* known values */ radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); /* XXX must check no carryout */ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; radiotap_hdr.rx_flags = 0; if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); } pradiotap_hdr = (struct rx_radiotap_hdr *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); } /* Take the data rate from the rxpd structure * only if the rate is auto */ if (adapter->auto_rate) adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate); wlan_compute_rssi(priv, prxpd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; libertas_upload_rx_packet(priv, skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "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; }
/* * Check mesh FW version and appropriately send the mesh start * command */ int lbs_init_mesh(struct lbs_private *priv) { struct net_device *dev = priv->dev; int ret = 0; lbs_deb_enter(LBS_DEB_MESH); priv->mesh_connect_status = LBS_DISCONNECTED; /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ /* 5.110.22 have mesh command with 0xa3 command id */ /* 10.0.0.p0 FW brings in mesh config command with different id */ /* Check FW version MSB and initialize mesh_fw_ver */ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX but we check them in that order because 20.pXX doesn't give an error -- it just silently fails. */ /* 5.110.20.pXX firmware will fail the command if the channel doesn't match the existing channel. But only if the TLV is correct. If the channel is wrong, _BOTH_ versions will give an error to 0x100+291, and allow 0x100+37 to succeed. It's just that 5.110.20.pXX will not have done anything useful */ priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel)) { priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel)) priv->mesh_tlv = 0; } } else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) { /* 10.0.0.pXX new firmwares should succeed with TLV * 0x100+37; Do not invoke command with old TLV. */ priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel)) priv->mesh_tlv = 0; } if (priv->mesh_tlv) { sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) netdev_err(dev, "cannot register lbs_mesh attribute\n"); ret = 1; } lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; }
static int wlan_cmd_802_11_set_wep(wlan_private * priv, struct cmd_ds_command *cmd, u32 cmd_act, void * pdata_buf) { struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep; wlan_adapter *adapter = priv->adapter; int ret = 0; struct assoc_request * assoc_req = pdata_buf; lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_SET_WEP); cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN); if (cmd_act == CMD_ACT_ADD) { int i; if (!assoc_req) { lbs_deb_cmd("Invalid association request!"); ret = -1; goto done; } wep->action = cpu_to_le16(CMD_ACT_ADD); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { struct enc_key * pkey = &assoc_req->wep_keys[i]; switch (pkey->len) { case KEY_LEN_WEP_40: wep->keytype[i] = CMD_TYPE_WEP_40_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: wep->keytype[i] = CMD_TYPE_WEP_104_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); break; case 0: break; default: lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", i, pkey->len); ret = -1; goto done; break; } } } else if (cmd_act == CMD_ACT_REMOVE) { /* ACT_REMOVE clears _all_ WEP keys */ wep->action = cpu_to_le16(CMD_ACT_REMOVE); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx); } ret = 0; done: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
/** * @brief This function prepare the command before send to firmware. * * @param priv A pointer to wlan_private structure * @param cmd_no command number * @param cmd_action command action: GET or SET * @param wait_option wait option: wait response or not * @param cmd_oid cmd oid: treated as sub command * @param pdata_buf A pointer to informaion buffer * @return 0 or -1 */ int libertas_prepare_and_send_command(wlan_private * priv, u16 cmd_no, u16 cmd_action, u16 wait_option, u32 cmd_oid, void *pdata_buf) { int ret = 0; wlan_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmdnode; struct cmd_ds_command *cmdptr; unsigned long flags; lbs_deb_enter(LBS_DEB_HOST); if (!adapter) { lbs_deb_host("PREP_CMD: adapter is NULL\n"); ret = -1; goto done; } if (adapter->surpriseremoved) { lbs_deb_host("PREP_CMD: card removed\n"); ret = -1; goto done; } cmdnode = libertas_get_free_cmd_ctrl_node(priv); if (cmdnode == NULL) { lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); /* Wake up main thread to execute next command */ wake_up_interruptible(&priv->waitq); ret = -1; goto done; } libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf); cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no); if (!cmdptr) { lbs_deb_host("PREP_CMD: cmdptr is NULL\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; } /* Set sequence number, command and INT option */ adapter->seqnum++; cmdptr->seqnum = cpu_to_le16(adapter->seqnum); cmdptr->command = cpu_to_le16(cmd_no); cmdptr->result = 0; switch (cmd_no) { case CMD_GET_HW_SPEC: ret = wlan_cmd_hw_spec(priv, cmdptr); break; case CMD_802_11_PS_MODE: ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); break; case CMD_802_11_SCAN: ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); break; case CMD_MAC_CONTROL: ret = wlan_cmd_mac_control(priv, cmdptr); break; case CMD_802_11_ASSOCIATE: case CMD_802_11_REASSOCIATE: ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); break; case CMD_802_11_DEAUTHENTICATE: ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); break; case CMD_802_11_SET_WEP: ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_AD_HOC_START: ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; case CMD_CODE_DNLD: break; case CMD_802_11_RESET: ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); break; case CMD_802_11_GET_LOG: ret = wlan_cmd_802_11_get_log(priv, cmdptr); break; case CMD_802_11_AUTHENTICATE: ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; case CMD_802_11_GET_STAT: ret = wlan_cmd_802_11_get_stat(priv, cmdptr); break; case CMD_802_11_SNMP_MIB: ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_RF_CHANNEL: ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_RF_TX_POWER: ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_RADIO_CONTROL: ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; case CMD_802_11_DATA_RATE: ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); break; case CMD_802_11_RATE_ADAPT_RATESET: ret = wlan_cmd_802_11_rate_adapt_rateset(priv, cmdptr, cmd_action); break; case CMD_MAC_MULTICAST_ADR: ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; case CMD_802_11_MONITOR_MODE: ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_AD_HOC_JOIN: ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; case CMD_802_11_RSSI: ret = wlan_cmd_802_11_rssi(priv, cmdptr); break; case CMD_802_11_AD_HOC_STOP: ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); break; case CMD_802_11_ENABLE_RSN: ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_KEY_MATERIAL: ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; case CMD_802_11_PAIRWISE_TSC: break; case CMD_802_11_GROUP_TSC: break; case CMD_802_11_MAC_ADDRESS: ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); break; case CMD_802_11_EEPROM_ACCESS: ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_SET_AFC: case CMD_802_11_GET_AFC: cmdptr->command = cpu_to_le16(cmd_no); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + S_DS_GEN); memmove(&cmdptr->params.afc, pdata_buf, sizeof(struct cmd_ds_802_11_afc)); ret = 0; goto done; case CMD_802_11D_DOMAIN_INFO: ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, cmd_no, cmd_action); break; case CMD_802_11_SLEEP_PARAMS: ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); break; case CMD_802_11_INACTIVITY_TIMEOUT: ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, cmd_action, pdata_buf); libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); break; case CMD_802_11_TPC_CFG: cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + S_DS_GEN); memmove(&cmdptr->params.tpccfg, pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); ret = 0; break; case CMD_802_11_LED_GPIO_CTRL: { struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio*) cmdptr->params.ledgpio.data; memmove(&cmdptr->params.ledgpio, pdata_buf, sizeof(struct cmd_ds_802_11_led_ctrl)); cmdptr->command = cpu_to_le16(CMD_802_11_LED_GPIO_CTRL); #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 cmdptr->size = cpu_to_le16(gpio->header.len + S_DS_GEN + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); gpio->header.len = cpu_to_le16(gpio->header.len); ret = 0; break; } case CMD_802_11_PWR_CFG: cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + S_DS_GEN); memmove(&cmdptr->params.pwrcfg, pdata_buf, sizeof(struct cmd_ds_802_11_pwr_cfg)); ret = 0; break; case CMD_BT_ACCESS: ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_FWT_ACCESS: ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_MESH_ACCESS: ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_SET_BOOT2_VER: ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_GET_TSF: cmdptr->command = cpu_to_le16(CMD_GET_TSF); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + S_DS_GEN); ret = 0; break; default: lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } /* return error, since the command preparation failed */ if (ret != 0) { lbs_deb_host("PREP_CMD: command preparation failed\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; } cmdnode->cmdwaitqwoken = 0; libertas_queue_cmd(adapter, cmdnode, 1); wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { lbs_deb_host("PREP_CMD: wait for response\n"); might_sleep(); wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); } spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd_retcode) { lbs_deb_host("PREP_CMD: command failed with return code %d\n", adapter->cur_cmd_retcode); adapter->cur_cmd_retcode = 0; ret = -1; } spin_unlock_irqrestore(&adapter->driver_lock, flags); done: lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
static int if_usb_prog_firmware(wlan_private * priv) { struct usb_card_rec *cardp = priv->card; int i = 0; static int reset_count = 10; int ret = 0; lbs_deb_enter(LBS_DEB_USB); cardp->rinfo.priv = priv; restart: if (if_usb_submit_rx_urb_fwload(priv) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); ret = -1; goto done; } cardp->bootcmdresp = 0; do { int j = 0; i++; /* Issue Boot command = 1, Boot from Download-FW */ if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); /* wait for command response */ do { j++; msleep_interruptible(100); } while (cardp->bootcmdresp == 0 && j < 10); } while (cardp->bootcmdresp == 0 && i < 5); if (cardp->bootcmdresp == 0) { if (--reset_count >= 0) { libertas_do_reset(priv); goto restart; } return -1; } i = 0; priv->adapter->fw_ready = 0; cardp->totalbytes = 0; cardp->fwlastblksent = 0; cardp->CRC_OK = 1; cardp->fwdnldover = 0; cardp->fwseqnum = -1; cardp->totalbytes = 0; cardp->fwfinalblk = 0; if_prog_firmware(priv); do { lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); i++; msleep_interruptible(100); if (priv->adapter->surpriseremoved || i >= 20) break; } while (!cardp->fwdnldover); if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { libertas_do_reset(priv); goto restart; } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); ret = -1; goto done; } if_usb_submit_rx_urb(priv); /* Delay 200 ms to waiting for the FW ready */ msleep_interruptible(200); priv->adapter->fw_ready = 1; done: lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; }
int lbs_process_event(struct lbs_private *priv, u32 event) { int ret = 0; struct cmd_header cmd; lbs_deb_enter(LBS_DEB_CMD); switch (event) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: link sensed\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: lbs_deb_cmd("EVENT: deauthenticated\n"); lbs_mac_event_disconnected(priv, false); break; case MACREG_INT_CODE_DISASSOCIATED: lbs_deb_cmd("EVENT: disassociated\n"); lbs_mac_event_disconnected(priv, false); break; case MACREG_INT_CODE_LINK_LOST_NO_SCAN: lbs_deb_cmd("EVENT: link lost\n"); lbs_mac_event_disconnected(priv, true); break; case MACREG_INT_CODE_PS_SLEEP: lbs_deb_cmd("EVENT: ps sleep\n"); /* handle unexpected PS SLEEP event */ if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n"); break; } if (!list_empty(&priv->cmdpendingq)) { lbs_deb_cmd("EVENT: commands in queue, do not sleep\n"); break; } priv->psstate = PS_STATE_PRE_SLEEP; lbs_ps_confirm_sleep(priv); break; case MACREG_INT_CODE_HOST_AWAKE: lbs_deb_cmd("EVENT: host awake\n"); if (priv->reset_deep_sleep_wakeup) priv->reset_deep_sleep_wakeup(priv); priv->is_deep_sleep = 0; lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd, sizeof(cmd)); priv->is_host_sleep_activated = 0; wake_up_interruptible(&priv->host_sleep_q); break; case MACREG_INT_CODE_DEEP_SLEEP_AWAKE: if (priv->reset_deep_sleep_wakeup) priv->reset_deep_sleep_wakeup(priv); lbs_deb_cmd("EVENT: ds awake\n"); priv->is_deep_sleep = 0; priv->wakeup_dev_required = 0; wake_up_interruptible(&priv->ds_awake_q); break; case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: ps awake\n"); /* handle unexpected PS AWAKE event */ if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } priv->psstate = PS_STATE_AWAKE; if (priv->needtowakeup) { /* * wait for the command processing to finish * before resuming sending * priv->needtowakeup will be set to FALSE * in lbs_ps_wakeup() */ lbs_deb_cmd("waking up ...\n"); lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false); } break; case MACREG_INT_CODE_MIC_ERR_UNICAST: lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); lbs_send_mic_failureevent(priv, event); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); lbs_send_mic_failureevent(priv, event); break; case MACREG_INT_CODE_MIB_CHANGED: lbs_deb_cmd("EVENT: MIB CHANGED\n"); break; case MACREG_INT_CODE_INIT_DONE: lbs_deb_cmd("EVENT: INIT DONE\n"); break; case MACREG_INT_CODE_ADHOC_BCN_LOST: lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: netdev_alert(priv->dev, "EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: netdev_alert(priv->dev, "EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: netdev_alert(priv->dev, "EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: netdev_alert(priv->dev, "EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: netdev_alert(priv->dev, "EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events */ netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; default: netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event); break; } lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", 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; }
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; /* Store the response code to cur_cmd_retcode. */ priv->cur_cmd_retcode = result; 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->mode == IW_MODE_ADHOC && action == CMD_SUBCMD_ENTER_PS) priv->psmode = LBS802_11POWERMODECAM; } else if (action == CMD_SUBCMD_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_ps_wakeup(priv, 0); mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); } } else if (action == CMD_SUBCMD_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); } else ret = handle_cmd_response(priv, 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; }
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; }