diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 9c783c5bef4878eaecd2a696a28dc8c8a1dcd0ef..b23b82e8287be8a64f15b1fe9eece7669775f2f7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1166,6 +1166,128 @@ static void hns3_tx_spare_reclaim_cb(struct hns3_enet_ring *ring, } } +static struct hns3_dhcp_packet *hns3_get_dhcp_packet(struct sk_buff *skb, + int *dhcp_len) +{ + struct hns3_dhcp_packet *dhcp; + union l4_hdr_info l4; + int l4_payload_len; + + l4.hdr = skb_transport_header(skb); + if (l4.udp->dest != htons(HNS3_DHCP_CLIENT_PORT) || + l4.udp->source != htons(HNS3_DHCP_SERVER_PORT)) + return NULL; + + dhcp = (struct hns3_dhcp_packet *)(l4.hdr + sizeof(struct udphdr)); + l4_payload_len = ntohs(l4.udp->len) - sizeof(struct udphdr); + if (l4_payload_len < offsetof(struct hns3_dhcp_packet, options) || + dhcp->hlen != ETH_ALEN || + dhcp->cookie != htonl(HNS3_DHCP_MAGIC)) + return NULL; + + *dhcp_len = l4_payload_len; + return dhcp; +} + +static u8 *hns3_dhcp_option_scan(struct hns3_dhcp_packet *packet, + struct hns3_dhcp_opt_state *opt_state) +{ + int opt_len; + u8 *cur_opt; + + /* option bytes: [code][len][data0~data[len-1]] */ + while (1) { + if (opt_state->rem <= 0) + break; + + switch (opt_state->opt_ptr[DHCP_OPT_CODE]) { + /* option padding and end have no len and data byte. */ + case DHCP_OPT_PADDING: + opt_state->rem--; + opt_state->opt_ptr++; + break; + case DHCP_OPT_END: + if (DHCP_OVERLOAD_USE_FILE(opt_state->overload_flag)) { + opt_state->overload_flag |= + DHCP_OVERLOAD_FILE_USED; + opt_state->opt_ptr = packet->file; + opt_state->rem = sizeof(packet->file); + break; + } + if (DHCP_OVERLOAD_USE_SNAME(opt_state->overload_flag)) { + opt_state->overload_flag |= + DHCP_OVERLOAD_SNAME_USED; + opt_state->opt_ptr = packet->sname; + opt_state->rem = sizeof(packet->sname); + break; + } + return NULL; + default: + if (opt_state->rem <= DHCP_OPT_LEN) + return NULL; + /* opt_len includes code, len and data bytes */ + opt_len = opt_state->opt_ptr[DHCP_OPT_LEN] + + DHCP_OPT_DATA; + cur_opt = opt_state->opt_ptr; + if (opt_state->rem < opt_len) + return NULL; + + opt_state->opt_ptr += opt_len; + opt_state->rem -= opt_len; + if (cur_opt[DHCP_OPT_CODE] == DHCP_OPT_OVERLOAD) { + opt_state->overload_flag |= + cur_opt[DHCP_OPT_DATA]; + break; + } + return cur_opt; + } + } + + return NULL; +} + +static void hns3_udhcp_update_option61(struct hns3_nic_priv *priv, + struct hns3_dhcp_packet *packet, + int dhcp_len) +{ + struct hns3_dhcp_opt_state opt_state; + u8 *cur_opt; + + opt_state.opt_ptr = packet->options; + opt_state.rem = dhcp_len - offsetof(struct hns3_dhcp_packet, options); + opt_state.overload_flag = 0; + + cur_opt = hns3_dhcp_option_scan(packet, &opt_state); + while (cur_opt) { + if (cur_opt[DHCP_OPT_CODE] != DHCP_OPT_CLIENT_ID) { + cur_opt = hns3_dhcp_option_scan(packet, &opt_state); + continue; + } + if (cur_opt[DHCP_OPT_LEN] > ETH_ALEN) + ether_addr_copy(&cur_opt[DHCP_CLIENT_ID_MAC_OFT], + priv->roh_perm_mac); + break; + } +} + +static void hns3_dhcp_packet_convert(struct hns3_nic_priv *priv, + struct sk_buff *skb, + struct hns3_dhcp_packet *dhcp, + int dhcp_len) +{ + const u8 roh_dhcp_mac[ETH_ALEN] = {0x0, 0x0, 0x0, 0xFF, 0xFF, 0x04}; + struct ethhdr *l2hdr = eth_hdr(skb); + + if (!dhcp) + return; + + ether_addr_copy(dhcp->chaddr, priv->roh_perm_mac); + hns3_udhcp_update_option61(priv, dhcp, dhcp_len); + + if (is_broadcast_ether_addr(l2hdr->h_source)) + ether_addr_copy(l2hdr->h_source, roh_dhcp_mac); +} + static int hns3_set_tso(struct sk_buff *skb, u32 *paylen_fdop_ol4cs, u16 *mss, u32 *type_cs_vlan_tso, u32 *send_bytes) { @@ -1717,7 +1839,20 @@ static int hns3_handle_csum_partial(struct hns3_enet_ring *ring, return 0; } -static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, +static bool hns3_roh_check_udpv4(struct sk_buff *skb) +{ + union l3_hdr_info l3; + + l3.hdr = skb_network_header(skb); + if (skb->protocol != htons(ETH_P_IP) || + l3.v4->version != IP_VERSION_IPV4) + return false; + + return l3.v4->protocol == IPPROTO_UDP; +} + +static int hns3_fill_skb_desc(struct hns3_nic_priv *priv, + struct hns3_enet_ring *ring, struct sk_buff *skb, struct hns3_desc *desc, struct hns3_desc_cb *desc_cb) { @@ -1742,6 +1877,15 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, hnae3_set_field(param.paylen_fdop_ol4cs, HNS3_TXD_FD_OP_M, HNS3_TXD_FD_OP_S, fd_op); + if (hnae3_check_roh_mac_type(priv->ae_handle) && + hns3_roh_check_udpv4(skb)) { + struct hns3_dhcp_packet *dhcp; + int dhcp_len; + + dhcp = hns3_get_dhcp_packet(skb, &dhcp_len); + hns3_dhcp_packet_convert(priv, skb, dhcp, dhcp_len); + } + /* Set txbd */ desc->tx.ol_type_vlan_len_msec = cpu_to_le32(param.ol_type_vlan_len_msec); @@ -2339,15 +2483,16 @@ static int hns3_handle_desc_filling(struct hns3_enet_ring *ring, return hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB); } -static int hns3_handle_skb_desc(struct hns3_enet_ring *ring, +static int hns3_handle_skb_desc(struct hns3_nic_priv *priv, + struct hns3_enet_ring *ring, struct sk_buff *skb, struct hns3_desc_cb *desc_cb, int next_to_use_head) { int ret; - ret = hns3_fill_skb_desc(ring, skb, &ring->desc[ring->next_to_use], - desc_cb); + ret = hns3_fill_skb_desc(priv, ring, skb, + &ring->desc[ring->next_to_use], desc_cb); if (unlikely(ret < 0)) goto fill_err; @@ -2396,7 +2541,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) goto out_err_tx_ok; } - ret = hns3_handle_skb_desc(ring, skb, desc_cb, ring->next_to_use); + ret = hns3_handle_skb_desc(priv, ring, skb, desc_cb, ring->next_to_use); if (unlikely(ret <= 0)) goto out_err_tx_ok; @@ -5225,6 +5370,10 @@ static int hns3_init_mac_addr(struct net_device *netdev) return 0; } + if (hnae3_check_roh_mac_type(h) && + is_zero_ether_addr(priv->roh_perm_mac)) + ether_addr_copy(priv->roh_perm_mac, netdev->dev_addr); + if (h->ae_algo->ops->set_mac_addr) ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true); @@ -5376,6 +5525,7 @@ static int hns3_client_init(struct hnae3_handle *handle) priv->tx_timeout_count = 0; priv->max_non_tso_bd_num = ae_dev->dev_specs.max_non_tso_bd_num; set_bit(HNS3_NIC_STATE_DOWN, &priv->state); + eth_zero_addr(priv->roh_perm_mac); handle->msg_enable = netif_msg_init(debug, DEFAULT_MSG_LEVEL); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index ccfd38b0028e923ae834aebc2bbbcddea0203a31..85c352fff83b79d8f99a2a78b1c774ead00dffbb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -604,6 +604,56 @@ struct hns3_nic_priv { struct hns3_enet_coalesce rx_coal; u32 tx_copybreak; u32 rx_copybreak; + u8 roh_perm_mac[ETH_ALEN]; +}; + +#define HNS3_DHCP_SERVER_PORT 68 +#define HNS3_DHCP_CLIENT_PORT 67 +#define HNS3_DHCP_MAGIC 0x63825363 +#define DHCP_OPT_CODE 0 +#define DHCP_OPT_LEN 1 +#define DHCP_OPT_DATA 2 +#define DHCP_CLIENT_ID_LEN 7 +#define DHCP_CLIENT_ID_MAC_OFT 3 +#define DHCP_OVERLOAD_FILE 0x1 +#define DHCP_OVERLOAD_SNAME 0x2 +#define DHCP_OVERLOAD_FILE_USED 0x101 +#define DHCP_OVERLOAD_SNAME_USED 0x202 +#define DHCP_OVERLOAD_USE_FILE(x) \ + (((x) & DHCP_OVERLOAD_FILE_USED) == DHCP_OVERLOAD_FILE) +#define DHCP_OVERLOAD_USE_SNAME(x) \ + (((x) & DHCP_OVERLOAD_SNAME_USED) == DHCP_OVERLOAD_SNAME) + +enum DHCP_OPTION_CODES { + DHCP_OPT_PADDING = 0, + DHCP_OPT_OVERLOAD = 52, + DHCP_OPT_CLIENT_ID = 61, + DHCP_OPT_END = 255 +}; + +struct hns3_dhcp_packet { + u8 op; + u8 htype; + u8 hlen; + u8 hops; + u32 xid; + u16 secs; + u16 flags; + u32 ciaddr; + u32 yiaddr; + u32 siaddr_nip; + u32 gateway_nip; + u8 chaddr[16]; /* link-layer client hardware address (MAC) */ + u8 sname[64]; + u8 file[128]; + u32 cookie; /* DHCP magic bytes: 0x63825363 */ + u8 options[312]; +}; + +struct hns3_dhcp_opt_state { + u8 *opt_ptr; /* refer to current option item */ + int rem; /* remain bytes in options */ + u32 overload_flag; /* whether use file and sname field as options */ }; union l3_hdr_info { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 6563c27fa7512e95d6b9d513f41eedf83a034e57..e84b967b4aa76312efb4fff44c7d979908840429 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2867,12 +2867,28 @@ static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability, if (fec_mode) *fec_mode = mac->fec_mode; } + +static void hclge_roh_convert_mac_addr(struct hclge_dev *hdev) +{ +#define HCLGE_ROH_EID_MASK_BYTE 3 + + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + + if (hnae3_check_roh_mac_type(handle)) { + if (!is_valid_ether_addr(hdev->hw.mac.mac_addr)) + random_ether_addr(hdev->hw.mac.mac_addr); + memset(hdev->hw.mac.mac_addr, 0, HCLGE_ROH_EID_MASK_BYTE); + } +} + static int hclge_mac_init(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; int ret; hclge_mac_type_init(hdev); + hclge_roh_convert_mac_addr(hdev); hdev->support_sfp_query = true; hdev->hw.mac.duplex = HCLGE_MAC_FULL;