diff options
author | Julian Wiedmann <jwi@linux.ibm.com> | 2021-01-28 12:25:50 +0100 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2021-01-28 20:35:58 -0800 |
commit | a667fee181b2c44cbf162f6a24c3594904aa9da1 (patch) | |
tree | b793a02137b2b85cbfd1e8c3b917bc44407a8f14 /drivers/s390/net | |
parent | c61dff3c1ef77f46e4aa605f71c68089b02b3d78 (diff) |
s390/qeth: make cast type selection for af_iucv skbs robust
As part of the TX queue selection for af_iucv skbs,
qeth_l3_get_cast_type_rcu() ends up calling qeth_get_ether_cast_type().
Which is rather fragile, since such skbs don't have a proper ETH header
and we rely on it being zeroed out in the right places. Add a separate
case for ETH_P_AF_IUCV instead that does the right thing.
When later building the HW header for such skbs, don't hard-code the
cast type but follow the same path as for other protocol types. Here
the cast type should naturally come from the skb's queue mapping.
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 4921afb51a1c..dd441eaec66e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1604,8 +1604,10 @@ static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst, 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); } } @@ -1651,14 +1653,6 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, } else { hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; - if (proto == 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, proto); /* some HW requires combined L3+L4 csum offload: */ @@ -1687,16 +1681,25 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, cast_type = qeth_l3_get_cast_type_rcu(skb, dst, proto); l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type); - if (proto == htons(ETH_P_IP)) { + switch (proto) { + case htons(ETH_P_IP): l3_hdr->next_hop.addr.s6_addr32[3] = qeth_next_hop_v4_rcu(skb, dst); - } else if (proto == htons(ETH_P_IPV6)) { + 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; } |