diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 94 |
1 files changed, 54 insertions, 40 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d138ac432d01..dd441eaec66e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1576,7 +1576,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst, - int ipv) + __be16 proto) { struct neighbour *n = NULL; @@ -1595,30 +1595,31 @@ static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst, } /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */ - switch (ipv) { - case 4: + switch (proto) { + case htons(ETH_P_IP): if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) return RTN_BROADCAST; return ipv4_is_multicast(ip_hdr(skb)->daddr) ? RTN_MULTICAST : RTN_UNICAST; - case 6: + case htons(ETH_P_IPV6): return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ? RTN_MULTICAST : RTN_UNICAST; + case htons(ETH_P_AF_IUCV): + return RTN_UNICAST; default: - /* ... and MAC address */ + /* OSA only: ... and MAC address */ return qeth_get_ether_cast_type(skb); } } -static int qeth_l3_get_cast_type(struct sk_buff *skb) +static int qeth_l3_get_cast_type(struct sk_buff *skb, __be16 proto) { - int ipv = qeth_get_ip_version(skb); struct dst_entry *dst; int cast_type; rcu_read_lock(); - dst = qeth_dst_check_rcu(skb, ipv); - cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv); + dst = qeth_dst_check_rcu(skb, proto); + cast_type = qeth_l3_get_cast_type_rcu(skb, dst, proto); rcu_read_unlock(); return cast_type; @@ -1637,7 +1638,7 @@ static u8 qeth_l3_cast_type_to_flag(int cast_type) static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, struct qeth_hdr *hdr, struct sk_buff *skb, - int ipv, unsigned int data_len) + __be16 proto, unsigned int data_len) { struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3; struct vlan_ethhdr *veth = vlan_eth_hdr(skb); @@ -1652,23 +1653,15 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, } else { hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; - if (skb->protocol == htons(ETH_P_AF_IUCV)) { - l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; - l3_hdr->next_hop.addr.s6_addr16[0] = htons(0xfe80); - memcpy(&l3_hdr->next_hop.addr.s6_addr32[2], - iucv_trans_hdr(skb)->destUserID, 8); - return; - } - if (skb->ip_summed == CHECKSUM_PARTIAL) { - qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); + qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, proto); /* some HW requires combined L3+L4 csum offload: */ - if (ipv == 4) + if (proto == htons(ETH_P_IP)) hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; } } - if (ipv == 4 || IS_IQD(card)) { + if (proto == htons(ETH_P_IP) || IS_IQD(card)) { /* NETIF_F_HW_VLAN_CTAG_TX */ if (skb_vlan_tag_present(skb)) { hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME; @@ -1680,24 +1673,33 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, } rcu_read_lock(); - dst = qeth_dst_check_rcu(skb, ipv); + dst = qeth_dst_check_rcu(skb, proto); if (IS_IQD(card) && skb_get_queue_mapping(skb) != QETH_IQD_MCAST_TXQ) cast_type = RTN_UNICAST; else - cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv); + cast_type = qeth_l3_get_cast_type_rcu(skb, dst, proto); l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type); - if (ipv == 4) { + switch (proto) { + case htons(ETH_P_IP): l3_hdr->next_hop.addr.s6_addr32[3] = qeth_next_hop_v4_rcu(skb, dst); - } else if (ipv == 6) { + break; + case htons(ETH_P_IPV6): l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, dst); hdr->hdr.l3.flags |= QETH_HDR_IPV6; if (!IS_IQD(card)) hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU; - } else { + break; + case htons(ETH_P_AF_IUCV): + l3_hdr->next_hop.addr.s6_addr16[0] = htons(0xfe80); + memcpy(&l3_hdr->next_hop.addr.s6_addr32[2], + iucv_trans_hdr(skb)->destUserID, 8); + l3_hdr->flags |= QETH_HDR_IPV6; + break; + default: /* OSA only: */ l3_hdr->flags |= QETH_HDR_PASSTHRU; } @@ -1719,7 +1721,7 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb) } static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, - struct qeth_qdio_out_q *queue, int ipv) + struct qeth_qdio_out_q *queue, __be16 proto) { unsigned int hw_hdr_len; int rc; @@ -1733,15 +1735,15 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, skb_pull(skb, ETH_HLEN); qeth_l3_fixup_headers(skb); - return qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header); + return qeth_xmit(card, skb, queue, proto, qeth_l3_fill_header); } static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + __be16 proto = vlan_get_protocol(skb); u16 txq = skb_get_queue_mapping(skb); - int ipv = qeth_get_ip_version(skb); struct qeth_qdio_out_q *queue; int rc; @@ -1752,22 +1754,32 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (card->options.sniffer) goto tx_drop; - if ((card->options.cq != QETH_CQ_ENABLED && !ipv) || - (card->options.cq == QETH_CQ_ENABLED && - skb->protocol != htons(ETH_P_AF_IUCV))) + + switch (proto) { + case htons(ETH_P_AF_IUCV): + if (card->options.cq != QETH_CQ_ENABLED) + goto tx_drop; + break; + case htons(ETH_P_IP): + case htons(ETH_P_IPV6): + if (card->options.cq == QETH_CQ_ENABLED) + goto tx_drop; + break; + default: goto tx_drop; + } } else { queue = card->qdio.out_qs[txq]; } if (!(dev->flags & IFF_BROADCAST) && - qeth_l3_get_cast_type(skb) == RTN_BROADCAST) + qeth_l3_get_cast_type(skb, proto) == RTN_BROADCAST) goto tx_drop; - if (ipv == 4 || IS_IQD(card)) - rc = qeth_l3_xmit(card, skb, queue, ipv); + if (proto == htons(ETH_P_IP) || IS_IQD(card)) + rc = qeth_l3_xmit(card, skb, queue, proto); else - rc = qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header); + rc = qeth_xmit(card, skb, queue, proto, qeth_l3_fill_header); if (!rc) return NETDEV_TX_OK; @@ -1813,7 +1825,7 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { - if (qeth_get_ip_version(skb) != 4) + if (vlan_get_protocol(skb) != htons(ETH_P_IP)) features &= ~NETIF_F_HW_VLAN_CTAG_TX; return qeth_features_check(skb, dev, features); } @@ -1821,8 +1833,10 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb, static u16 qeth_l3_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { - return qeth_iqd_select_queue(dev, skb, qeth_l3_get_cast_type(skb), - sb_dev); + __be16 proto = vlan_get_protocol(skb); + + return qeth_iqd_select_queue(dev, skb, + qeth_l3_get_cast_type(skb, proto), sb_dev); } static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb, @@ -1971,7 +1985,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE) - qeth_set_offline(card, false); + qeth_set_offline(card, card->discipline, false); cancel_work_sync(&card->close_dev_work); if (card->dev->reg_state == NETREG_REGISTERED) |