diff options
author | Ursula Braun <ursula.braun@de.ibm.com> | 2010-01-10 21:50:50 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-13 23:34:55 -0500 |
commit | 76b11f8e270f04851774ff64b16e29e5a43d3a1a (patch) | |
tree | d4e7666c766bd1fba5ef2219717f302faf3a21bf /drivers/s390/net/qeth_l3_main.c | |
parent | ab8932f3e8e07df92d6ce3fa41f5af0dda865429 (diff) |
qeth: HiperSockets Network Traffic Analyzer
New feature to trace HiperSockets network traffic for debugging
purposes.
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 174 |
1 files changed, 150 insertions, 24 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fd1b6ed3721f..337d03fb045d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -242,6 +242,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, | |||
242 | struct qeth_ipaddr *tmp, *t; | 242 | struct qeth_ipaddr *tmp, *t; |
243 | int found = 0; | 243 | int found = 0; |
244 | 244 | ||
245 | if (card->options.sniffer) | ||
246 | return 0; | ||
245 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { | 247 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { |
246 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && | 248 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && |
247 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) | 249 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) |
@@ -457,6 +459,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
457 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); | 459 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); |
458 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); | 460 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); |
459 | 461 | ||
462 | if (card->options.sniffer) | ||
463 | return; | ||
460 | spin_lock_irqsave(&card->ip_lock, flags); | 464 | spin_lock_irqsave(&card->ip_lock, flags); |
461 | tbd_list = card->ip_tbd_list; | 465 | tbd_list = card->ip_tbd_list; |
462 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); | 466 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); |
@@ -495,7 +499,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
495 | spin_unlock_irqrestore(&card->ip_lock, flags); | 499 | spin_unlock_irqrestore(&card->ip_lock, flags); |
496 | rc = qeth_l3_deregister_addr_entry(card, addr); | 500 | rc = qeth_l3_deregister_addr_entry(card, addr); |
497 | spin_lock_irqsave(&card->ip_lock, flags); | 501 | spin_lock_irqsave(&card->ip_lock, flags); |
498 | if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED)) | 502 | if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED)) |
499 | kfree(addr); | 503 | kfree(addr); |
500 | else | 504 | else |
501 | list_add_tail(&addr->entry, &card->ip_list); | 505 | list_add_tail(&addr->entry, &card->ip_list); |
@@ -513,6 +517,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, | |||
513 | unsigned long flags; | 517 | unsigned long flags; |
514 | 518 | ||
515 | QETH_DBF_TEXT(TRACE, 4, "clearip"); | 519 | QETH_DBF_TEXT(TRACE, 4, "clearip"); |
520 | if (recover && card->options.sniffer) | ||
521 | return; | ||
516 | spin_lock_irqsave(&card->ip_lock, flags); | 522 | spin_lock_irqsave(&card->ip_lock, flags); |
517 | /* clear todo list */ | 523 | /* clear todo list */ |
518 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { | 524 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { |
@@ -1674,6 +1680,76 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) | |||
1674 | return rc; | 1680 | return rc; |
1675 | } | 1681 | } |
1676 | 1682 | ||
1683 | static int | ||
1684 | qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, | ||
1685 | unsigned long data) | ||
1686 | { | ||
1687 | struct qeth_ipa_cmd *cmd; | ||
1688 | __u16 rc; | ||
1689 | |||
1690 | QETH_DBF_TEXT(SETUP, 2, "diastrcb"); | ||
1691 | |||
1692 | cmd = (struct qeth_ipa_cmd *)data; | ||
1693 | rc = cmd->hdr.return_code; | ||
1694 | if (rc) { | ||
1695 | QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); | ||
1696 | if (cmd->data.diagass.action == QETH_DIAGS_CMD_TRACE_ENABLE) { | ||
1697 | switch (rc) { | ||
1698 | case IPA_RC_HARDWARE_AUTH_ERROR: | ||
1699 | dev_warn(&card->gdev->dev, "The device is not " | ||
1700 | "authorized to run as a HiperSockets " | ||
1701 | "network traffic analyzer\n"); | ||
1702 | break; | ||
1703 | case IPA_RC_TRACE_ALREADY_ACTIVE: | ||
1704 | dev_warn(&card->gdev->dev, "A HiperSockets " | ||
1705 | "network traffic analyzer is already " | ||
1706 | "active in the HiperSockets LAN\n"); | ||
1707 | break; | ||
1708 | default: | ||
1709 | break; | ||
1710 | } | ||
1711 | } | ||
1712 | return 0; | ||
1713 | } | ||
1714 | |||
1715 | switch (cmd->data.diagass.action) { | ||
1716 | case QETH_DIAGS_CMD_TRACE_QUERY: | ||
1717 | break; | ||
1718 | case QETH_DIAGS_CMD_TRACE_DISABLE: | ||
1719 | card->info.promisc_mode = SET_PROMISC_MODE_OFF; | ||
1720 | dev_info(&card->gdev->dev, "The HiperSockets network traffic " | ||
1721 | "analyzer is deactivated\n"); | ||
1722 | break; | ||
1723 | case QETH_DIAGS_CMD_TRACE_ENABLE: | ||
1724 | card->info.promisc_mode = SET_PROMISC_MODE_ON; | ||
1725 | dev_info(&card->gdev->dev, "The HiperSockets network traffic " | ||
1726 | "analyzer is activated\n"); | ||
1727 | break; | ||
1728 | default: | ||
1729 | QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", | ||
1730 | cmd->data.diagass.action, QETH_CARD_IFNAME(card)); | ||
1731 | } | ||
1732 | |||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | static int | ||
1737 | qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) | ||
1738 | { | ||
1739 | struct qeth_cmd_buffer *iob; | ||
1740 | struct qeth_ipa_cmd *cmd; | ||
1741 | |||
1742 | QETH_DBF_TEXT(SETUP, 2, "diagtrac"); | ||
1743 | |||
1744 | iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); | ||
1745 | cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); | ||
1746 | cmd->data.diagass.subcmd_len = 16; | ||
1747 | cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; | ||
1748 | cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; | ||
1749 | cmd->data.diagass.action = diags_cmd; | ||
1750 | return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); | ||
1751 | } | ||
1752 | |||
1677 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, | 1753 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, |
1678 | struct net_device *dev) | 1754 | struct net_device *dev) |
1679 | { | 1755 | { |
@@ -1951,7 +2027,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1951 | case QETH_CAST_ANYCAST: | 2027 | case QETH_CAST_ANYCAST: |
1952 | case QETH_CAST_NOCAST: | 2028 | case QETH_CAST_NOCAST: |
1953 | default: | 2029 | default: |
1954 | skb->pkt_type = PACKET_HOST; | 2030 | if (card->options.sniffer) |
2031 | skb->pkt_type = PACKET_OTHERHOST; | ||
2032 | else | ||
2033 | skb->pkt_type = PACKET_HOST; | ||
1955 | memcpy(tg_addr, card->dev->dev_addr, | 2034 | memcpy(tg_addr, card->dev->dev_addr, |
1956 | card->dev->addr_len); | 2035 | card->dev->addr_len); |
1957 | } | 2036 | } |
@@ -2007,7 +2086,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2007 | int offset; | 2086 | int offset; |
2008 | __u16 vlan_tag = 0; | 2087 | __u16 vlan_tag = 0; |
2009 | unsigned int len; | 2088 | unsigned int len; |
2010 | |||
2011 | /* get first element of current buffer */ | 2089 | /* get first element of current buffer */ |
2012 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 2090 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; |
2013 | offset = 0; | 2091 | offset = 0; |
@@ -2026,7 +2104,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2026 | case QETH_HEADER_TYPE_LAYER3: | 2104 | case QETH_HEADER_TYPE_LAYER3: |
2027 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2105 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
2028 | len = skb->len; | 2106 | len = skb->len; |
2029 | if (vlan_tag) | 2107 | if (vlan_tag && !card->options.sniffer) |
2030 | if (card->vlangrp) | 2108 | if (card->vlangrp) |
2031 | vlan_hwaccel_rx(skb, card->vlangrp, | 2109 | vlan_hwaccel_rx(skb, card->vlangrp, |
2032 | vlan_tag); | 2110 | vlan_tag); |
@@ -2037,6 +2115,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2037 | else | 2115 | else |
2038 | netif_rx(skb); | 2116 | netif_rx(skb); |
2039 | break; | 2117 | break; |
2118 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | ||
2119 | skb->pkt_type = PACKET_HOST; | ||
2120 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
2121 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
2122 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2123 | else | ||
2124 | skb->ip_summed = CHECKSUM_NONE; | ||
2125 | len = skb->len; | ||
2126 | netif_receive_skb(skb); | ||
2127 | break; | ||
2040 | default: | 2128 | default: |
2041 | dev_kfree_skb_any(skb); | 2129 | dev_kfree_skb_any(skb); |
2042 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); | 2130 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); |
@@ -2118,6 +2206,9 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2118 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 2206 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
2119 | 2207 | ||
2120 | qeth_set_allowed_threads(card, 0, 1); | 2208 | qeth_set_allowed_threads(card, 0, 1); |
2209 | if (card->options.sniffer && | ||
2210 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) | ||
2211 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2121 | if (card->read.state == CH_STATE_UP && | 2212 | if (card->read.state == CH_STATE_UP && |
2122 | card->write.state == CH_STATE_UP && | 2213 | card->write.state == CH_STATE_UP && |
2123 | (card->state == CARD_STATE_UP)) { | 2214 | (card->state == CARD_STATE_UP)) { |
@@ -2162,6 +2253,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2162 | return rc; | 2253 | return rc; |
2163 | } | 2254 | } |
2164 | 2255 | ||
2256 | /* | ||
2257 | * test for and Switch promiscuous mode (on or off) | ||
2258 | * either for guestlan or HiperSocket Sniffer | ||
2259 | */ | ||
2260 | static void | ||
2261 | qeth_l3_handle_promisc_mode(struct qeth_card *card) | ||
2262 | { | ||
2263 | struct net_device *dev = card->dev; | ||
2264 | |||
2265 | if (((dev->flags & IFF_PROMISC) && | ||
2266 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || | ||
2267 | (!(dev->flags & IFF_PROMISC) && | ||
2268 | (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) | ||
2269 | return; | ||
2270 | |||
2271 | if (card->info.guestlan) { /* Guestlan trace */ | ||
2272 | if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | ||
2273 | qeth_setadp_promisc_mode(card); | ||
2274 | } else if (card->options.sniffer && /* HiperSockets trace */ | ||
2275 | qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { | ||
2276 | if (dev->flags & IFF_PROMISC) { | ||
2277 | QETH_DBF_TEXT(TRACE, 3, "+promisc"); | ||
2278 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE); | ||
2279 | } else { | ||
2280 | QETH_DBF_TEXT(TRACE, 3, "-promisc"); | ||
2281 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2282 | } | ||
2283 | } | ||
2284 | } | ||
2285 | |||
2165 | static void qeth_l3_set_multicast_list(struct net_device *dev) | 2286 | static void qeth_l3_set_multicast_list(struct net_device *dev) |
2166 | { | 2287 | { |
2167 | struct qeth_card *card = dev->ml_priv; | 2288 | struct qeth_card *card = dev->ml_priv; |
@@ -2170,15 +2291,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) | |||
2170 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && | 2291 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && |
2171 | (card->state != CARD_STATE_UP)) | 2292 | (card->state != CARD_STATE_UP)) |
2172 | return; | 2293 | return; |
2173 | qeth_l3_delete_mc_addresses(card); | 2294 | if (!card->options.sniffer) { |
2174 | qeth_l3_add_multicast_ipv4(card); | 2295 | qeth_l3_delete_mc_addresses(card); |
2296 | qeth_l3_add_multicast_ipv4(card); | ||
2175 | #ifdef CONFIG_QETH_IPV6 | 2297 | #ifdef CONFIG_QETH_IPV6 |
2176 | qeth_l3_add_multicast_ipv6(card); | 2298 | qeth_l3_add_multicast_ipv6(card); |
2177 | #endif | 2299 | #endif |
2178 | qeth_l3_set_ip_addr_list(card); | 2300 | qeth_l3_set_ip_addr_list(card); |
2179 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 2301 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
2180 | return; | 2302 | return; |
2181 | qeth_setadp_promisc_mode(card); | 2303 | } |
2304 | qeth_l3_handle_promisc_mode(card); | ||
2182 | } | 2305 | } |
2183 | 2306 | ||
2184 | static const char *qeth_l3_arp_get_error_cause(int *rc) | 2307 | static const char *qeth_l3_arp_get_error_cause(int *rc) |
@@ -2778,8 +2901,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2778 | int nr_frags; | 2901 | int nr_frags; |
2779 | 2902 | ||
2780 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2903 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2781 | (skb->protocol != htons(ETH_P_IPV6)) && | 2904 | (((skb->protocol != htons(ETH_P_IPV6)) && |
2782 | (skb->protocol != htons(ETH_P_IP))) | 2905 | (skb->protocol != htons(ETH_P_IP))) || |
2906 | card->options.sniffer)) | ||
2783 | goto tx_drop; | 2907 | goto tx_drop; |
2784 | 2908 | ||
2785 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 2909 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
@@ -3155,7 +3279,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | |||
3155 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 3279 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
3156 | buffer = &card->qdio.in_q->bufs[index]; | 3280 | buffer = &card->qdio.in_q->bufs[index]; |
3157 | if (!(qdio_err && | 3281 | if (!(qdio_err && |
3158 | qeth_check_qdio_errors(buffer->buffer, | 3282 | qeth_check_qdio_errors(card, buffer->buffer, |
3159 | qdio_err, "qinerr"))) | 3283 | qdio_err, "qinerr"))) |
3160 | qeth_l3_process_inbound_buffer(card, buffer, index); | 3284 | qeth_l3_process_inbound_buffer(card, buffer, index); |
3161 | /* clear buffer and give back to hardware */ | 3285 | /* clear buffer and give back to hardware */ |
@@ -3250,20 +3374,22 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3250 | goto out_remove; | 3374 | goto out_remove; |
3251 | } else | 3375 | } else |
3252 | card->lan_online = 1; | 3376 | card->lan_online = 1; |
3253 | qeth_l3_set_large_send(card, card->options.large_send); | ||
3254 | 3377 | ||
3255 | rc = qeth_l3_setadapter_parms(card); | 3378 | rc = qeth_l3_setadapter_parms(card); |
3256 | if (rc) | 3379 | if (rc) |
3257 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3380 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3258 | rc = qeth_l3_start_ipassists(card); | 3381 | if (!card->options.sniffer) { |
3259 | if (rc) | 3382 | rc = qeth_l3_start_ipassists(card); |
3260 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | 3383 | if (rc) |
3261 | rc = qeth_l3_setrouting_v4(card); | 3384 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); |
3262 | if (rc) | 3385 | qeth_l3_set_large_send(card, card->options.large_send); |
3263 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); | 3386 | rc = qeth_l3_setrouting_v4(card); |
3264 | rc = qeth_l3_setrouting_v6(card); | 3387 | if (rc) |
3265 | if (rc) | 3388 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); |
3266 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | 3389 | rc = qeth_l3_setrouting_v6(card); |
3390 | if (rc) | ||
3391 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
3392 | } | ||
3267 | netif_tx_disable(card->dev); | 3393 | netif_tx_disable(card->dev); |
3268 | 3394 | ||
3269 | rc = qeth_init_qdio_queues(card); | 3395 | rc = qeth_init_qdio_queues(card); |