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, 72 insertions, 22 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fafb8c299540..e4c1176ee25b 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -29,6 +29,7 @@ #include <net/ip.h> #include <net/arp.h> #include <net/ip6_checksum.h> +#include <net/iucv/af_iucv.h> #include "qeth_l3.h" @@ -267,7 +268,7 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, } } -static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) +int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) { unsigned long flags; int rc = 0; @@ -286,7 +287,7 @@ static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) return rc; } -static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) +int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) { unsigned long flags; int rc = 0; @@ -305,7 +306,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) } -static struct qeth_ipaddr *qeth_l3_get_addr_buffer( +struct qeth_ipaddr *qeth_l3_get_addr_buffer( enum qeth_prot_versions prot) { struct qeth_ipaddr *addr; @@ -421,7 +422,7 @@ again: list_splice(&fail_list, &card->ip_list); } -static void qeth_l3_set_ip_addr_list(struct qeth_card *card) +void qeth_l3_set_ip_addr_list(struct qeth_card *card) { struct list_head *tbd_list; struct qeth_ipaddr *todo, *addr; @@ -438,7 +439,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) spin_lock_irqsave(&card->ip_lock, flags); tbd_list = card->ip_tbd_list; - card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); + card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_ATOMIC); if (!card->ip_tbd_list) { QETH_CARD_TEXT(card, 0, "silnomem"); card->ip_tbd_list = tbd_list; @@ -1414,7 +1415,7 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) return 0; } -int qeth_l3_set_rx_csum(struct qeth_card *card, int on) +static int qeth_l3_set_rx_csum(struct qeth_card *card, int on) { int rc = 0; @@ -1993,12 +1994,13 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, __u16 vlan_tag = 0; int is_vlan; unsigned int len; + __u16 magic; *done = 0; BUG_ON(!budget); while (budget) { skb = qeth_core_get_next_skb(card, - card->qdio.in_q->bufs[card->rx.b_index].buffer, + &card->qdio.in_q->bufs[card->rx.b_index], &card->rx.b_element, &card->rx.e_offset, &hdr); if (!skb) { *done = 1; @@ -2007,12 +2009,26 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, skb->dev = card->dev; switch (hdr->hdr.l3.id) { case QETH_HEADER_TYPE_LAYER3: - is_vlan = qeth_l3_rebuild_skb(card, skb, hdr, + magic = *(__u16 *)skb->data; + if ((card->info.type == QETH_CARD_TYPE_IQD) && + (magic == ETH_P_AF_IUCV)) { + skb->protocol = ETH_P_AF_IUCV; + skb->pkt_type = PACKET_HOST; + skb->mac_header = NET_SKB_PAD; + skb->dev = card->dev; + len = skb->len; + card->dev->header_ops->create(skb, card->dev, 0, + card->dev->dev_addr, "FAKELL", + card->dev->addr_len); + netif_receive_skb(skb); + } else { + is_vlan = qeth_l3_rebuild_skb(card, skb, hdr, &vlan_tag); - len = skb->len; - if (is_vlan && !card->options.sniffer) - __vlan_hwaccel_put_tag(skb, vlan_tag); - napi_gro_receive(&card->napi, skb); + len = skb->len; + if (is_vlan && !card->options.sniffer) + __vlan_hwaccel_put_tag(skb, vlan_tag); + napi_gro_receive(&card->napi, skb); + } break; case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ skb->pkt_type = PACKET_HOST; @@ -2784,6 +2800,30 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) return cast_type; } +static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, + struct qeth_hdr *hdr, struct sk_buff *skb) +{ + char daddr[16]; + struct af_iucv_trans_hdr *iucv_hdr; + + skb_pull(skb, 14); + card->dev->header_ops->create(skb, card->dev, 0, + card->dev->dev_addr, card->dev->dev_addr, + card->dev->addr_len); + skb_pull(skb, 14); + iucv_hdr = (struct af_iucv_trans_hdr *)skb->data; + memset(hdr, 0, sizeof(struct qeth_hdr)); + hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; + hdr->hdr.l3.ext_flags = 0; + hdr->hdr.l3.length = skb->len; + hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; + memset(daddr, 0, sizeof(daddr)); + daddr[0] = 0xfe; + daddr[1] = 0x80; + memcpy(&daddr[8], iucv_hdr->destUserID, 8); + memcpy(hdr->hdr.l3.dest_addr, daddr, 16); +} + static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { @@ -2936,8 +2976,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int data_offset = -1; int nr_frags; - if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) || - card->options.sniffer) + if (((card->info.type == QETH_CARD_TYPE_IQD) && + (((card->options.cq != QETH_CQ_ENABLED) && !ipv) || + ((card->options.cq == QETH_CQ_ENABLED) && + (skb->protocol != ETH_P_AF_IUCV)))) || + card->options.sniffer) goto tx_drop; if ((card->state != CARD_STATE_UP) || !card->lan_online) { @@ -2959,7 +3002,10 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { new_skb = skb; - data_offset = ETH_HLEN; + if (new_skb->protocol == ETH_P_AF_IUCV) + data_offset = 0; + else + data_offset = ETH_HLEN; hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); if (!hdr) goto tx_drop; @@ -2993,7 +3039,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) tag = (u16 *)(new_skb->data + 12); *tag = __constant_htons(ETH_P_8021Q); *(tag + 1) = htons(vlan_tx_tag_get(new_skb)); - new_skb->vlan_tci = 0; } } @@ -3025,9 +3070,13 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); } else { - qeth_l3_fill_header(card, hdr, new_skb, ipv, - cast_type); - hdr->hdr.l3.length = new_skb->len - data_offset; + if (new_skb->protocol == ETH_P_AF_IUCV) + qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb); + else { + qeth_l3_fill_header(card, hdr, new_skb, ipv, + cast_type); + hdr->hdr.l3.length = new_skb->len - data_offset; + } } if (skb->ip_summed == CHECKSUM_PARTIAL) @@ -3226,7 +3275,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_set_rx_mode = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, .ndo_fix_features = qeth_l3_fix_features, @@ -3242,7 +3291,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_set_rx_mode = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, .ndo_fix_features = qeth_l3_fix_features, @@ -3290,6 +3339,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->flags |= IFF_NOARP; card->dev->netdev_ops = &qeth_l3_netdev_ops; qeth_l3_iqd_read_initial_mac(card); + if (card->options.hsuid[0]) + memcpy(card->dev->perm_addr, card->options.hsuid, 9); } else return -ENODEV; @@ -3660,7 +3711,6 @@ static int qeth_l3_ip6_event(struct notifier_block *this, struct qeth_ipaddr *addr; struct qeth_card *card; - card = qeth_l3_get_card_from_dev(dev); if (!card) return NOTIFY_DONE; |