예제 #1
0
static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
{
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	int i;

	if (!nic_data->vf)
		return;

	for (i = 0; i < efx->vf_count; i++) {
		struct ef10_vf *vf = nic_data->vf + i;

#if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_PCI_DEV_FLAGS_ASSIGNED)
		/* If VF is assigned, do not free the vport  */
		if (vf->pci_dev &&
		    vf->pci_dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
			continue;
#endif

		if (vf->vport_assigned) {
			efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i);
			vf->vport_assigned = 0;
		}

		if (!is_zero_ether_addr(vf->mac)) {
			efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
			eth_zero_addr(vf->mac);
		}

		if (vf->vport_id) {
			efx_ef10_vport_free(efx, vf->vport_id);
			vf->vport_id = 0;
		}

		vf->efx = NULL;
	}
}
예제 #2
0
/*
 * This function resets the connection state.
 *
 * The function is invoked after receiving a disconnect event from firmware,
 * and performs the following actions -
 *      - Set media status to disconnected
 *      - Clean up Tx and Rx packets
 *      - Resets SNR/NF/RSSI value in driver
 *      - Resets security configurations in driver
 *      - Enables auto data rate
 *      - Saves the previous SSID and BSSID so that they can
 *        be used for re-association, if required
 *      - Erases current SSID and BSSID information
 *      - Sends a disconnect event to upper layers/applications.
 */
void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code,
				 bool from_ap)
{
	struct mwifiex_adapter *adapter = priv->adapter;

	if (!priv->media_connected)
		return;

	mwifiex_dbg(adapter, INFO,
		    "info: handles disconnect event\n");

	priv->media_connected = false;

	priv->scan_block = false;
	priv->port_open = false;

	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
	    ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) {
		mwifiex_disable_all_tdls_links(priv);

		if (priv->adapter->auto_tdls)
			mwifiex_clean_auto_tdls(priv);
	}

	/* Free Tx and Rx packets, report disconnect to upper layer */
	mwifiex_clean_txrx(priv);

	/* Reset SNR/NF/RSSI values */
	priv->data_rssi_last = 0;
	priv->data_nf_last = 0;
	priv->data_rssi_avg = 0;
	priv->data_nf_avg = 0;
	priv->bcn_rssi_last = 0;
	priv->bcn_nf_last = 0;
	priv->bcn_rssi_avg = 0;
	priv->bcn_nf_avg = 0;
	priv->rxpd_rate = 0;
	priv->rxpd_htinfo = 0;
	priv->sec_info.wpa_enabled = false;
	priv->sec_info.wpa2_enabled = false;
	priv->wpa_ie_len = 0;

	priv->sec_info.wapi_enabled = false;
	priv->wapi_ie_len = 0;
	priv->sec_info.wapi_key_on = false;

	priv->sec_info.encryption_mode = 0;

	/* Enable auto data rate */
	priv->is_data_rate_auto = true;
	priv->data_rate = 0;

	priv->assoc_resp_ht_param = 0;
	priv->ht_param_present = false;

	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
	     GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data)
		mwifiex_hist_data_reset(priv);

	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
		priv->adhoc_state = ADHOC_IDLE;
		priv->adhoc_is_link_sensed = false;
	}

	/*
	 * Memorize the previous SSID and BSSID so
	 * it could be used for re-assoc
	 */

	mwifiex_dbg(adapter, INFO,
		    "info: previous SSID=%s, SSID len=%u\n",
		    priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);

	mwifiex_dbg(adapter, INFO,
		    "info: current SSID=%s, SSID len=%u\n",
		    priv->curr_bss_params.bss_descriptor.ssid.ssid,
		    priv->curr_bss_params.bss_descriptor.ssid.ssid_len);

	memcpy(&priv->prev_ssid,
	       &priv->curr_bss_params.bss_descriptor.ssid,
	       sizeof(struct cfg80211_ssid));

	memcpy(priv->prev_bssid,
	       priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN);

	/* Need to erase the current SSID and BSSID info */
	memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));

	adapter->tx_lock_flag = false;
	adapter->pps_uapsd_mode = false;

	if (test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags) &&
	    adapter->curr_cmd)
		return;
	priv->media_connected = false;
	mwifiex_dbg(adapter, MSG,
		    "info: successfully disconnected from %pM: reason code %d\n",
		    priv->cfg_bssid, reason_code);
	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
	    priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
		cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
				      !from_ap, GFP_KERNEL);
	}
	eth_zero_addr(priv->cfg_bssid);

	mwifiex_stop_net_dev_queue(priv->netdev, adapter);
	if (netif_carrier_ok(priv->netdev))
		netif_carrier_off(priv->netdev);

	if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info))
		return;

	mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG,
			 HostCmd_ACT_GEN_REMOVE, 0, NULL, false);
}
static int rtl_op_set_key( struct ieee80211_hw *hw, enum set_key_cmd cmd,
			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
			  struct ieee80211_key_conf *key )
{
	struct rtl_priv *rtlpriv = rtl_priv( hw );
	struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) );
	u8 key_type = NO_ENCRYPTION;
	u8 key_idx;
	bool group_key = false;
	bool wep_only = false;
	int err = 0;
	u8 mac_addr[ETH_ALEN];
	u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

	if ( rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec ) {
		RT_TRACE( rtlpriv, COMP_ERR, DBG_WARNING,
			 "not open hw encryption\n" );
		return -ENOSPC;	/*User disabled HW-crypto */
	}
	/* To support IBSS, use sw-crypto for GTK */
	if ( ( ( vif->type == NL80211_IFTYPE_ADHOC ) ||
	     ( vif->type == NL80211_IFTYPE_MESH_POINT ) ) &&
	      !( key->flags & IEEE80211_KEY_FLAG_PAIRWISE ) )
		return -ENOSPC;
	RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
		 "%s hardware based encryption for keyidx: %d, mac: %pM\n",
		 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
		 sta ? sta->addr : bcast_addr );
	rtlpriv->sec.being_setkey = true;
	rtl_ips_nic_on( hw );
	mutex_lock( &rtlpriv->locks.conf_mutex );
	/* <1> get encryption alg */

	switch ( key->cipher ) {
	case WLAN_CIPHER_SUITE_WEP40:
		key_type = WEP40_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP40\n" );
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP104\n" );
		key_type = WEP104_ENCRYPTION;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		key_type = TKIP_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:TKIP\n" );
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		key_type = AESCCMP_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n" );
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
		/*HW doesn't support CMAC encryption, use software CMAC */
		key_type = AESCMAC_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n" );
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
			 "HW don't support CMAC encryption, use software CMAC\n" );
		err = -EOPNOTSUPP;
		goto out_unlock;
	default:
		RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
			 key->cipher );
		goto out_unlock;
	}
	if ( key_type == WEP40_ENCRYPTION ||
			key_type == WEP104_ENCRYPTION ||
			mac->opmode == NL80211_IFTYPE_ADHOC )
		rtlpriv->sec.use_defaultkey = true;

	/* <2> get key_idx */
	key_idx = ( u8 ) ( key->keyidx );
	if ( key_idx > 3 )
		goto out_unlock;
	/* <3> if pairwise key enable_hw_sec */
	group_key = !( key->flags & IEEE80211_KEY_FLAG_PAIRWISE );

	/* wep always be group key, but there are two conditions:
	 * 1 ) wep only: is just for wep enc, in this condition
	 * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
	 * will be true & enable_hw_sec will be set when wep
	 * key setting.
	 * 2 ) wep( group ) + AES( pairwise ): some AP like cisco
	 * may use it, in this condition enable_hw_sec will not
	 * be set when wep key setting */
	/* we must reset sec_info after lingked before set key,
	 * or some flag will be wrong*/
	if ( vif->type == NL80211_IFTYPE_AP ||
	    vif->type == NL80211_IFTYPE_MESH_POINT ) {
		if ( !group_key || key_type == WEP40_ENCRYPTION ||
			key_type == WEP104_ENCRYPTION ) {
			if ( group_key )
				wep_only = true;
			rtlpriv->cfg->ops->enable_hw_sec( hw );
		}
	} else {
		if ( ( !group_key ) || ( mac->opmode == NL80211_IFTYPE_ADHOC ) ||
		     rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION ) {
			if ( rtlpriv->sec.pairwise_enc_algorithm ==
			    NO_ENCRYPTION &&
			    ( key_type == WEP40_ENCRYPTION ||
			    key_type == WEP104_ENCRYPTION ) )
				wep_only = true;
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5)\n",
				 key_type );
			rtlpriv->cfg->ops->enable_hw_sec( hw );
		}
	}
	/* <4> set key based on cmd */
	switch ( cmd ) {
	case SET_KEY:
		if ( wep_only ) {
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set WEP(group/pairwise) key\n" );
			/* Pairwise key with an assigned MAC address. */
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			rtlpriv->sec.group_enc_algorithm = key_type;
			/*set local buf about wep key. */
			memcpy( rtlpriv->sec.key_buf[key_idx],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[key_idx] = key->keylen;
			eth_zero_addr( mac_addr );
		} else if ( group_key ) {	/* group key */
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set group key\n" );
			/* group key */
			rtlpriv->sec.group_enc_algorithm = key_type;
			/*set local buf about group key. */
			memcpy( rtlpriv->sec.key_buf[key_idx],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[key_idx] = key->keylen;
			memcpy( mac_addr, bcast_addr, ETH_ALEN );
		} else {	/* pairwise key */
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set pairwise key\n" );
			if ( !sta ) {
				RT_ASSERT( false,
					  "pairwise key without mac_addr\n" );

				err = -EOPNOTSUPP;
				goto out_unlock;
			}
			/* Pairwise key with an assigned MAC address. */
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			/*set local buf about pairwise key. */
			memcpy( rtlpriv->sec.key_buf[PAIRWISE_KEYIDX],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen;
			rtlpriv->sec.pairwise_key =
			    rtlpriv->sec.key_buf[PAIRWISE_KEYIDX];
			memcpy( mac_addr, sta->addr, ETH_ALEN );
		}
		rtlpriv->cfg->ops->set_key( hw, key_idx, mac_addr,
					   group_key, key_type, wep_only,
					   false );
		/* <5> tell mac80211 do something: */
		/*must use sw generate IV, or can not work !!!!. */
		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
		key->hw_key_idx = key_idx;
		if ( key_type == TKIP_ENCRYPTION )
			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
		/*use software CCMP encryption for management frames ( MFP ) */
		if ( key_type == AESCCMP_ENCRYPTION )
			key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
		break;
	case DISABLE_KEY:
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
			 "disable key delete one entry\n" );
		/*set local buf about wep key. */
		if ( vif->type == NL80211_IFTYPE_AP ||
		    vif->type == NL80211_IFTYPE_MESH_POINT ) {
			if ( sta )
				rtl_cam_del_entry( hw, sta->addr );
		}
		memset( rtlpriv->sec.key_buf[key_idx], 0, key->keylen );
		rtlpriv->sec.key_len[key_idx] = 0;
		eth_zero_addr( mac_addr );
		/*
		 *mac80211 will delete entrys one by one,
		 *so don't use rtl_cam_reset_all_entry
		 *or clear all entry here.
		 */
		rtl_cam_delete_one_entry( hw, mac_addr, key_idx );

		rtl_cam_reset_sec_info( hw );

		break;
	default:
		RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG,
			 "cmd_err:%x!!!!\n", cmd );
	}
out_unlock:
	mutex_unlock( &rtlpriv->locks.conf_mutex );
	rtlpriv->sec.being_setkey = false;
	return err;
}
예제 #4
0
파일: cfg80211.c 프로젝트: mkrufky/linux
static int
qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
	     struct cfg80211_connect_params *sme)
{
	struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
	struct qtnf_wmac *mac = wiphy_priv(wiphy);
	struct cfg80211_chan_def chandef;
	struct qtnf_bss_config *bss_cfg;
	int ret;

	if (vif->wdev.iftype != NL80211_IFTYPE_STATION)
		return -EOPNOTSUPP;

	if (vif->sta_state != QTNF_STA_DISCONNECTED)
		return -EBUSY;

	bss_cfg = &vif->bss_cfg;
	memset(bss_cfg, 0, sizeof(*bss_cfg));

	if (sme->channel) {
		/* FIXME: need to set proper nl80211_channel_type value */
		cfg80211_chandef_create(&chandef, sme->channel,
					NL80211_CHAN_HT20);
		/* fall-back to minimal safe chandef description */
		if (!cfg80211_chandef_valid(&chandef))
			cfg80211_chandef_create(&chandef, sme->channel,
						NL80211_CHAN_HT20);

		memcpy(&mac->chandef, &chandef, sizeof(mac->chandef));
	}

	bss_cfg->ssid_len = sme->ssid_len;
	memcpy(&bss_cfg->ssid, sme->ssid, bss_cfg->ssid_len);
	bss_cfg->auth_type = sme->auth_type;
	bss_cfg->privacy = sme->privacy;
	bss_cfg->mfp = sme->mfp;

	if ((sme->bg_scan_period > 0) &&
	    (sme->bg_scan_period <= QTNF_MAX_BG_SCAN_PERIOD))
		bss_cfg->bg_scan_period = sme->bg_scan_period;
	else if (sme->bg_scan_period == -1)
		bss_cfg->bg_scan_period = QTNF_DEFAULT_BG_SCAN_PERIOD;
	else
		bss_cfg->bg_scan_period = 0; /* disabled */

	bss_cfg->connect_flags = 0;

	if (sme->flags & ASSOC_REQ_DISABLE_HT)
		bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_HT;
	if (sme->flags & ASSOC_REQ_DISABLE_VHT)
		bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT;
	if (sme->flags & ASSOC_REQ_USE_RRM)
		bss_cfg->connect_flags |= QLINK_STA_CONNECT_USE_RRM;

	memcpy(&bss_cfg->crypto, &sme->crypto, sizeof(bss_cfg->crypto));
	if (sme->bssid)
		ether_addr_copy(bss_cfg->bssid, sme->bssid);
	else
		eth_zero_addr(bss_cfg->bssid);

	ret = qtnf_cmd_send_connect(vif, sme);
	if (ret) {
		pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid,
		       vif->vifid);
		return ret;
	}

	vif->sta_state = QTNF_STA_CONNECTING;
	return 0;
}
예제 #5
0
파일: cfg80211.c 프로젝트: mkrufky/linux
static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
						  const char *name,
						  unsigned char name_assign_t,
						  enum nl80211_iftype type,
						  struct vif_params *params)
{
	struct qtnf_wmac *mac;
	struct qtnf_vif *vif;
	u8 *mac_addr = NULL;

	mac = wiphy_priv(wiphy);

	if (!mac)
		return ERR_PTR(-EFAULT);

	switch (type) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_AP:
		vif = qtnf_mac_get_free_vif(mac);
		if (!vif) {
			pr_err("MAC%u: no free VIF available\n", mac->macid);
			return ERR_PTR(-EFAULT);
		}

		eth_zero_addr(vif->mac_addr);
		vif->bss_priority = QTNF_DEF_BSS_PRIORITY;
		vif->wdev.wiphy = wiphy;
		vif->wdev.iftype = type;
		vif->sta_state = QTNF_STA_DISCONNECTED;
		break;
	default:
		pr_err("MAC%u: unsupported IF type %d\n", mac->macid, type);
		return ERR_PTR(-ENOTSUPP);
	}

	if (params)
		mac_addr = params->macaddr;

	if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) {
		pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid);
		goto err_cmd;
	}

	if (!is_valid_ether_addr(vif->mac_addr)) {
		pr_err("VIF%u.%u: FW reported bad MAC: %pM\n",
		       mac->macid, vif->vifid, vif->mac_addr);
		goto err_mac;
	}

	if (qtnf_core_net_attach(mac, vif, name, name_assign_t, type)) {
		pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid,
		       vif->vifid);
		goto err_net;
	}

	vif->wdev.netdev = vif->netdev;
	return &vif->wdev;

err_net:
	vif->netdev = NULL;
err_mac:
	qtnf_cmd_send_del_intf(vif);
err_cmd:
	vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;

	return ERR_PTR(-EFAULT);
}
예제 #6
0
파일: lg-vl600.c 프로젝트: 020gzh/linux
static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
	struct vl600_frame_hdr *frame;
	struct vl600_pkt_hdr *packet;
	struct ethhdr *ethhdr;
	int packet_len, count;
	struct sk_buff *buf = skb;
	struct sk_buff *clone;
	struct vl600_state *s = dev->driver_priv;

	/* Frame lengths are generally 4B multiplies but every couple of
	 * hours there's an odd number of bytes sized yet correct frame,
	 * so don't require this.  */

	/* Allow a packet (or multiple packets batched together) to be
	 * split across many frames.  We don't allow a new batch to
	 * begin in the same frame another one is ending however, and no
	 * leading or trailing pad bytes.  */
	if (s->current_rx_buf) {
		frame = (struct vl600_frame_hdr *) s->current_rx_buf->data;
		if (skb->len + s->current_rx_buf->len >
				le32_to_cpup(&frame->len)) {
			netif_err(dev, ifup, dev->net, "Fragment too long\n");
			dev->net->stats.rx_length_errors++;
			goto error;
		}

		buf = s->current_rx_buf;
		memcpy(skb_put(buf, skb->len), skb->data, skb->len);
	} else if (skb->len < 4) {
		netif_err(dev, ifup, dev->net, "Frame too short\n");
		dev->net->stats.rx_length_errors++;
		goto error;
	}

	frame = (struct vl600_frame_hdr *) buf->data;
	/* Yes, check that frame->magic == 0x53544448 (or 0x44544d48),
	 * otherwise we may run out of memory w/a bad packet */
	if (ntohl(frame->magic) != 0x53544448 &&
			ntohl(frame->magic) != 0x44544d48)
		goto error;

	if (buf->len < sizeof(*frame) ||
			buf->len != le32_to_cpup(&frame->len)) {
		/* Save this fragment for later assembly */
		if (s->current_rx_buf)
			return 0;

		s->current_rx_buf = skb_copy_expand(skb, 0,
				le32_to_cpup(&frame->len), GFP_ATOMIC);
		if (!s->current_rx_buf) {
			netif_err(dev, ifup, dev->net, "Reserving %i bytes "
					"for packet assembly failed.\n",
					le32_to_cpup(&frame->len));
			dev->net->stats.rx_errors++;
		}

		return 0;
	}

	count = le32_to_cpup(&frame->pkt_cnt);

	skb_pull(buf, sizeof(*frame));

	while (count--) {
		if (buf->len < sizeof(*packet)) {
			netif_err(dev, ifup, dev->net, "Packet too short\n");
			goto error;
		}

		packet = (struct vl600_pkt_hdr *) buf->data;
		packet_len = sizeof(*packet) + le32_to_cpup(&packet->len);
		if (packet_len > buf->len) {
			netif_err(dev, ifup, dev->net,
					"Bad packet length stored in header\n");
			goto error;
		}

		/* Packet header is same size as the ethernet header
		 * (sizeof(*packet) == sizeof(*ethhdr)), additionally
		 * the h_proto field is in the same place so we just leave it
		 * alone and fill in the remaining fields.
		 */
		ethhdr = (struct ethhdr *) skb->data;
		if (be16_to_cpup(&ethhdr->h_proto) == ETH_P_ARP &&
				buf->len > 0x26) {
			/* Copy the addresses from packet contents */
			memcpy(ethhdr->h_source,
					&buf->data[sizeof(*ethhdr) + 0x8],
					ETH_ALEN);
			memcpy(ethhdr->h_dest,
					&buf->data[sizeof(*ethhdr) + 0x12],
					ETH_ALEN);
		} else {
			eth_zero_addr(ethhdr->h_source);
			memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN);

			/* Inbound IPv6 packets have an IPv4 ethertype (0x800)
			 * for some reason.  Peek at the L3 header to check
			 * for IPv6 packets, and set the ethertype to IPv6
			 * (0x86dd) so Linux can understand it.
			 */
			if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
				ethhdr->h_proto = htons(ETH_P_IPV6);
		}

		if (count) {
			/* Not the last packet in this batch */
			clone = skb_clone(buf, GFP_ATOMIC);
			if (!clone)
				goto error;

			skb_trim(clone, packet_len);
			usbnet_skb_return(dev, clone);

			skb_pull(buf, (packet_len + 3) & ~3);
		} else {
			skb_trim(buf, packet_len);

			if (s->current_rx_buf) {
				usbnet_skb_return(dev, buf);
				s->current_rx_buf = NULL;
				return 0;
			}

			return 1;
		}
	}

error:
	if (s->current_rx_buf) {
		dev_kfree_skb_any(s->current_rx_buf);
		s->current_rx_buf = NULL;
	}
	dev->net->stats.rx_errors++;
	return 0;
}
예제 #7
0
파일: en_selftest.c 프로젝트: lumag/linux
static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
{
	struct sk_buff *skb = NULL;
	struct mlx5ehdr *mlxh;
	struct ethhdr *ethh;
	struct udphdr *udph;
	struct iphdr *iph;
	int datalen, iplen;

	datalen = MLX5E_TEST_PKT_SIZE -
		  (sizeof(*ethh) + sizeof(*iph) + sizeof(*udph));

	skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
	if (!skb) {
		netdev_err(priv->netdev, "\tFailed to alloc loopback skb\n");
		return NULL;
	}

	prefetchw(skb->data);
	skb_reserve(skb, NET_IP_ALIGN);

	/*  Reserve for ethernet and IP header  */
	ethh = skb_push(skb, ETH_HLEN);
	skb_reset_mac_header(skb);

	skb_set_network_header(skb, skb->len);
	iph = skb_put(skb, sizeof(struct iphdr));

	skb_set_transport_header(skb, skb->len);
	udph = skb_put(skb, sizeof(struct udphdr));

	/* Fill ETH header */
	ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr);
	eth_zero_addr(ethh->h_source);
	ethh->h_proto = htons(ETH_P_IP);

	/* Fill UDP header */
	udph->source = htons(9);
	udph->dest = htons(9); /* Discard Protocol */
	udph->len = htons(datalen + sizeof(struct udphdr));
	udph->check = 0;

	/* Fill IP header */
	iph->ihl = 5;
	iph->ttl = 32;
	iph->version = 4;
	iph->protocol = IPPROTO_UDP;
	iplen = sizeof(struct iphdr) + sizeof(struct udphdr) + datalen;
	iph->tot_len = htons(iplen);
	iph->frag_off = 0;
	iph->saddr = 0;
	iph->daddr = 0;
	iph->tos = 0;
	iph->id = 0;
	ip_send_check(iph);

	/* Fill test header and data */
	mlxh = skb_put(skb, sizeof(*mlxh));
	mlxh->version = 0;
	mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
	strlcpy(mlxh->text, mlx5e_test_text, sizeof(mlxh->text));
	datalen -= sizeof(*mlxh);
	skb_put_zero(skb, datalen);

	skb->csum = 0;
	skb->ip_summed = CHECKSUM_PARTIAL;
	udp4_hwcsum(skb, iph->saddr, iph->daddr);

	skb->protocol = htons(ETH_P_IP);
	skb->pkt_type = PACKET_HOST;
	skb->dev = priv->netdev;

	return skb;
}
예제 #8
0
int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
			       u8 qos)
{
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	struct ef10_vf *vf;
	u16 old_vlan, new_vlan;
	int rc = 0, rc2 = 0;

	if (vf_i >= efx->vf_count)
		return -EINVAL;
	if (qos != 0)
		return -EINVAL;

	vf = nic_data->vf + vf_i;

	new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan;
	if (new_vlan == vf->vlan)
		return 0;

	if (vf->efx) {
		efx_device_detach_sync(vf->efx);
		efx_net_stop(vf->efx->net_dev);

		down_write(&vf->efx->filter_sem);
		vf->efx->type->filter_table_remove(vf->efx);

		rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
		if (rc)
			goto restore_filters;
	}

	if (vf->vport_assigned) {
		rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
		if (rc) {
			netif_warn(efx, drv, efx->net_dev,
				   "Failed to change vlan on VF %d.\n", vf_i);
			netif_warn(efx, drv, efx->net_dev,
				   "This is likely because the VF is bound to a driver in a VM.\n");
			netif_warn(efx, drv, efx->net_dev,
				   "Please unload the driver in the VM.\n");
			goto restore_vadaptor;
		}
		vf->vport_assigned = 0;
	}

	if (!is_zero_ether_addr(vf->mac)) {
		rc = efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
		if (rc)
			goto restore_evb_port;
	}

	if (vf->vport_id) {
		rc = efx_ef10_vport_free(efx, vf->vport_id);
		if (rc)
			goto restore_mac;
		vf->vport_id = 0;
	}

	/* Do the actual vlan change */
	old_vlan = vf->vlan;
	vf->vlan = new_vlan;

	/* Restore everything in reverse order */
	rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
			MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
			vf->vlan, &vf->vport_id);
	if (rc)
		goto reset_nic;

restore_mac:
	if (!is_zero_ether_addr(vf->mac)) {
		rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
		if (rc2) {
			eth_zero_addr(vf->mac);
			goto reset_nic;
		}
	}

restore_evb_port:
	rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
	if (rc2)
		goto reset_nic;
	else
		vf->vport_assigned = 1;

restore_vadaptor:
	if (vf->efx) {
		rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
		if (rc2)
			goto reset_nic;
	}

restore_filters:
	if (vf->efx) {
		rc2 = vf->efx->type->filter_table_probe(vf->efx);
		if (rc2)
			goto reset_nic;

		rc2 = efx_net_open(vf->efx->net_dev);
		if (rc2)
			goto reset_nic;

		up_write(&vf->efx->filter_sem);

		netif_device_attach(vf->efx->net_dev);
	}

	return rc;

reset_nic:
	if (vf->efx) {
		up_write(&vf->efx->filter_sem);

		netif_err(efx, drv, efx->net_dev,
			  "Failed to restore the VF - scheduling reset.\n");

		efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH);
	} else {
		netif_err(efx, drv, efx->net_dev,
			  "Failed to restore the VF and cannot reset the VF "
			  "- VF is not functional.\n");
		netif_err(efx, drv, efx->net_dev,
			  "Please reload the driver attached to the VF.\n");
	}

	return rc ? rc : rc2;
}
예제 #9
0
int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac)
{
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	struct ef10_vf *vf;
	int rc;

	if (nic_data->vf == NULL)
		return -EOPNOTSUPP;

	if (vf_i >= efx->vf_count)
		return -EINVAL;
	vf = nic_data->vf + vf_i;

	if (vf->efx) {
		efx_device_detach_sync(vf->efx);
		efx_net_stop(vf->efx->net_dev);

		down_write(&vf->efx->filter_sem);
		vf->efx->type->filter_table_remove(vf->efx);

		rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
		if (rc) {
			up_write(&vf->efx->filter_sem);
			return rc;
		}
	}

	rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
	if (rc)
		return rc;

	if (!is_zero_ether_addr(vf->mac)) {
		rc = efx_ef10_vport_del_vf_mac(efx, vf->vport_id, vf->mac);
		if (rc)
			return rc;
	}

	if (!is_zero_ether_addr(mac)) {
		rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac);
		if (rc) {
			eth_zero_addr(vf->mac);
			goto fail;
		}
		if (vf->efx)
			ether_addr_copy(vf->efx->net_dev->dev_addr, mac);
	}
	ether_addr_copy(vf->mac, mac);

	rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
	if (rc)
		goto fail;

	if (vf->efx) {
		/* VF cannot use the vport_id that the PF created */
		rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
		if (rc) {
			up_write(&vf->efx->filter_sem);
			return rc;
		}
		vf->efx->type->filter_table_probe(vf->efx);
		up_write(&vf->efx->filter_sem);
		efx_net_open(vf->efx->net_dev);
		netif_device_attach(vf->efx->net_dev);
	}

	return 0;

fail:
	memset(vf->mac, 0, ETH_ALEN);
	return rc;
}
예제 #10
0
/* On top of the default firmware vswitch setup, create a VEB vswitch and
 * expansion vport for use by this function.
 */
int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	struct net_device *net_dev = efx->net_dev;
	int rc;

#if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_SRIOV_GET_TOTALVFS)
	if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0 && !enable_vswitch) {
#else
	if (efx->max_vfs <= 0 && !enable_vswitch) {
#endif
		/* vswitch not needed as we have no VFs */
		efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
		return 0;
	}

	rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED,
				    MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB);
	if (rc)
		goto fail1;

	rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
				  MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
				  EFX_EF10_NO_VLAN, &nic_data->vport_id);
	if (rc)
		goto fail2;
	efx->ef10_resources.vport_id = nic_data->vport_id;

	rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr);
	if (rc)
		goto fail3;
	ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr);

	rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
	if (rc)
		goto fail4;

	return 0;
fail4:
	efx_ef10_vport_del_mac(efx, nic_data->vport_id, nic_data->vport_mac);
	eth_zero_addr(nic_data->vport_mac);
fail3:
	efx_ef10_vport_free(efx, nic_data->vport_id);
	nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
fail2:
	efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED);
fail1:
	return rc;
#else
	return 0;
#endif
}

int efx_ef10_vswitching_probe_vf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	struct efx_ef10_nic_data *nic_data = efx->nic_data;

	return efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
#else
	return 0;
#endif
}

int efx_ef10_vswitching_restore_pf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	int rc;

	if (!nic_data->must_probe_vswitching)
		return 0;

	rc = efx_ef10_vswitching_probe_pf(efx);
	if (rc)
		goto fail;

	rc = efx_ef10_sriov_restore_vf_vswitching(efx);
	if (rc)
		goto fail;

	nic_data->must_probe_vswitching = false;
fail:
	return rc;
#else
	return 0;
#endif
}

int efx_ef10_vswitching_restore_vf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	struct efx_ef10_nic_data *nic_data = efx->nic_data;
	int rc;

	if (!nic_data->must_probe_vswitching)
		return 0;

	rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
	if (rc)
		return rc;

	nic_data->must_probe_vswitching = false;
#endif
	return 0;
}

void efx_ef10_vswitching_remove_pf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	struct efx_ef10_nic_data *nic_data = efx->nic_data;

	efx_ef10_sriov_free_vf_vswitching(efx);

	efx_ef10_vadaptor_free(efx, nic_data->vport_id);

	if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED)
		return; /* No vswitch was ever created */

	if (!is_zero_ether_addr(nic_data->vport_mac)) {
		efx_ef10_vport_del_mac(efx, nic_data->vport_id,
				       efx->net_dev->dev_addr);
		eth_zero_addr(nic_data->vport_mac);
	}

	efx_ef10_vport_free(efx, nic_data->vport_id);
	nic_data->vport_id = EVB_PORT_ID_ASSIGNED;

#if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_PCI_DEV_FLAGS_ASSIGNED)
	/* Only free the vswitch if no VFs are assigned */
	if (!pci_vfs_assigned(efx->pci_dev))
#endif
		efx_ef10_vswitch_free(efx, nic_data->vport_id);
#endif
}

void efx_ef10_vswitching_remove_vf(struct efx_nic *efx)
{
#ifdef CONFIG_SFC_SRIOV
	efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
#endif
}