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 | |
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>
-rw-r--r-- | drivers/s390/net/qeth_core.h | 5 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 130 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_mpc.h | 44 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_sys.c | 8 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 3 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3.h | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 174 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 56 |
8 files changed, 336 insertions, 86 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index b232693378cd..a3ac4456e0b1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -649,6 +649,7 @@ struct qeth_card_options { | |||
649 | int performance_stats; | 649 | int performance_stats; |
650 | int rx_sg_cb; | 650 | int rx_sg_cb; |
651 | enum qeth_ipa_isolation_modes isolation; | 651 | enum qeth_ipa_isolation_modes isolation; |
652 | int sniffer; | ||
652 | }; | 653 | }; |
653 | 654 | ||
654 | /* | 655 | /* |
@@ -737,6 +738,7 @@ struct qeth_card { | |||
737 | struct qeth_discipline discipline; | 738 | struct qeth_discipline discipline; |
738 | atomic_t force_alloc_skb; | 739 | atomic_t force_alloc_skb; |
739 | struct service_level qeth_service_level; | 740 | struct service_level qeth_service_level; |
741 | struct qdio_ssqd_desc ssqd; | ||
740 | }; | 742 | }; |
741 | 743 | ||
742 | struct qeth_card_list_struct { | 744 | struct qeth_card_list_struct { |
@@ -811,7 +813,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, | |||
811 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, | 813 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, |
812 | enum qeth_ipa_cmds, enum qeth_prot_versions); | 814 | enum qeth_ipa_cmds, enum qeth_prot_versions); |
813 | int qeth_query_setadapterparms(struct qeth_card *); | 815 | int qeth_query_setadapterparms(struct qeth_card *); |
814 | int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *); | 816 | int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *, |
817 | unsigned int, const char *); | ||
815 | void qeth_queue_input_buffer(struct qeth_card *, int); | 818 | void qeth_queue_input_buffer(struct qeth_card *, int); |
816 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, | 819 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, |
817 | struct qdio_buffer *, struct qdio_buffer_element **, int *, | 820 | struct qdio_buffer *, struct qdio_buffer_element **, int *, |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d34804d5ece1..2c8e9da8753f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) | |||
269 | card->qdio.init_pool.buf_count = bufcnt; | 269 | card->qdio.init_pool.buf_count = bufcnt; |
270 | return qeth_alloc_buffer_pool(card); | 270 | return qeth_alloc_buffer_pool(card); |
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); | ||
272 | 273 | ||
273 | static int qeth_issue_next_read(struct qeth_card *card) | 274 | static int qeth_issue_next_read(struct qeth_card *card) |
274 | { | 275 | { |
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, | |||
350 | if (IS_IPA(iob->data)) { | 351 | if (IS_IPA(iob->data)) { |
351 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); | 352 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); |
352 | if (IS_IPA_REPLY(cmd)) { | 353 | if (IS_IPA_REPLY(cmd)) { |
353 | if (cmd->hdr.command < IPA_CMD_SETCCID || | 354 | if (cmd->hdr.command != IPA_CMD_SETCCID && |
354 | cmd->hdr.command > IPA_CMD_MODCCID) | 355 | cmd->hdr.command != IPA_CMD_DELCCID && |
356 | cmd->hdr.command != IPA_CMD_MODCCID && | ||
357 | cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) | ||
355 | qeth_issue_ipa_msg(cmd, | 358 | qeth_issue_ipa_msg(cmd, |
356 | cmd->hdr.return_code, card); | 359 | cmd->hdr.return_code, card); |
357 | return cmd; | 360 | return cmd; |
@@ -1100,11 +1103,6 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1100 | card->thread_running_mask = 0; | 1103 | card->thread_running_mask = 0; |
1101 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); | 1104 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); |
1102 | INIT_LIST_HEAD(&card->ip_list); | 1105 | INIT_LIST_HEAD(&card->ip_list); |
1103 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); | ||
1104 | if (!card->ip_tbd_list) { | ||
1105 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); | ||
1106 | return -ENOMEM; | ||
1107 | } | ||
1108 | INIT_LIST_HEAD(card->ip_tbd_list); | 1106 | INIT_LIST_HEAD(card->ip_tbd_list); |
1109 | INIT_LIST_HEAD(&card->cmd_waiter_list); | 1107 | INIT_LIST_HEAD(&card->cmd_waiter_list); |
1110 | init_waitqueue_head(&card->wait_q); | 1108 | init_waitqueue_head(&card->wait_q); |
@@ -1138,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void) | |||
1138 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); | 1136 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); |
1139 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); | 1137 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); |
1140 | if (!card) | 1138 | if (!card) |
1141 | return NULL; | 1139 | goto out; |
1142 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 1140 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
1143 | if (qeth_setup_channel(&card->read)) { | 1141 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); |
1144 | kfree(card); | 1142 | if (!card->ip_tbd_list) { |
1145 | return NULL; | 1143 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); |
1146 | } | 1144 | goto out_card; |
1147 | if (qeth_setup_channel(&card->write)) { | ||
1148 | qeth_clean_channel(&card->read); | ||
1149 | kfree(card); | ||
1150 | return NULL; | ||
1151 | } | 1145 | } |
1146 | if (qeth_setup_channel(&card->read)) | ||
1147 | goto out_ip; | ||
1148 | if (qeth_setup_channel(&card->write)) | ||
1149 | goto out_channel; | ||
1152 | card->options.layer2 = -1; | 1150 | card->options.layer2 = -1; |
1153 | card->qeth_service_level.seq_print = qeth_core_sl_print; | 1151 | card->qeth_service_level.seq_print = qeth_core_sl_print; |
1154 | register_service_level(&card->qeth_service_level); | 1152 | register_service_level(&card->qeth_service_level); |
1155 | return card; | 1153 | return card; |
1154 | |||
1155 | out_channel: | ||
1156 | qeth_clean_channel(&card->read); | ||
1157 | out_ip: | ||
1158 | kfree(card->ip_tbd_list); | ||
1159 | out_card: | ||
1160 | kfree(card); | ||
1161 | out: | ||
1162 | return NULL; | ||
1156 | } | 1163 | } |
1157 | 1164 | ||
1158 | static int qeth_determine_card_type(struct qeth_card *card) | 1165 | static int qeth_determine_card_type(struct qeth_card *card) |
@@ -2573,8 +2580,8 @@ int qeth_query_setadapterparms(struct qeth_card *card) | |||
2573 | } | 2580 | } |
2574 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); | 2581 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); |
2575 | 2582 | ||
2576 | int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | 2583 | int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, |
2577 | const char *dbftext) | 2584 | unsigned int qdio_error, const char *dbftext) |
2578 | { | 2585 | { |
2579 | if (qdio_error) { | 2586 | if (qdio_error) { |
2580 | QETH_DBF_TEXT(TRACE, 2, dbftext); | 2587 | QETH_DBF_TEXT(TRACE, 2, dbftext); |
@@ -2584,7 +2591,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | |||
2584 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", | 2591 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", |
2585 | buf->element[14].flags & 0xff); | 2592 | buf->element[14].flags & 0xff); |
2586 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); | 2593 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); |
2587 | return 1; | 2594 | if ((buf->element[15].flags & 0xff) == 0x12) { |
2595 | card->stats.rx_dropped++; | ||
2596 | return 0; | ||
2597 | } else | ||
2598 | return 1; | ||
2588 | } | 2599 | } |
2589 | return 0; | 2600 | return 0; |
2590 | } | 2601 | } |
@@ -2667,7 +2678,7 @@ static int qeth_handle_send_error(struct qeth_card *card, | |||
2667 | qdio_err = 1; | 2678 | qdio_err = 1; |
2668 | } | 2679 | } |
2669 | } | 2680 | } |
2670 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); | 2681 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr"); |
2671 | 2682 | ||
2672 | if (!qdio_err) | 2683 | if (!qdio_err) |
2673 | return QETH_SEND_ERROR_NONE; | 2684 | return QETH_SEND_ERROR_NONE; |
@@ -3509,6 +3520,7 @@ void qeth_tx_timeout(struct net_device *dev) | |||
3509 | { | 3520 | { |
3510 | struct qeth_card *card; | 3521 | struct qeth_card *card; |
3511 | 3522 | ||
3523 | QETH_DBF_TEXT(TRACE, 4, "txtimeo"); | ||
3512 | card = dev->ml_priv; | 3524 | card = dev->ml_priv; |
3513 | card->stats.tx_errors++; | 3525 | card->stats.tx_errors++; |
3514 | qeth_schedule_recovery(card); | 3526 | qeth_schedule_recovery(card); |
@@ -3847,9 +3859,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, | |||
3847 | 3859 | ||
3848 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3860 | int qeth_core_hardsetup_card(struct qeth_card *card) |
3849 | { | 3861 | { |
3850 | struct qdio_ssqd_desc *ssqd; | ||
3851 | int retries = 0; | 3862 | int retries = 0; |
3852 | int mpno = 0; | ||
3853 | int rc; | 3863 | int rc; |
3854 | 3864 | ||
3855 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); | 3865 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); |
@@ -3882,31 +3892,6 @@ retriable: | |||
3882 | else | 3892 | else |
3883 | goto retry; | 3893 | goto retry; |
3884 | } | 3894 | } |
3885 | |||
3886 | rc = qeth_get_unitaddr(card); | ||
3887 | if (rc) { | ||
3888 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | ||
3889 | return rc; | ||
3890 | } | ||
3891 | |||
3892 | ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); | ||
3893 | if (!ssqd) { | ||
3894 | rc = -ENOMEM; | ||
3895 | goto out; | ||
3896 | } | ||
3897 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||
3898 | if (rc == 0) | ||
3899 | mpno = ssqd->pcnt; | ||
3900 | kfree(ssqd); | ||
3901 | |||
3902 | if (mpno) | ||
3903 | mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||
3904 | if (card->info.portno > mpno) { | ||
3905 | QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d" | ||
3906 | "\n.", CARD_BUS_ID(card), card->info.portno); | ||
3907 | rc = -ENODEV; | ||
3908 | goto out; | ||
3909 | } | ||
3910 | qeth_init_tokens(card); | 3895 | qeth_init_tokens(card); |
3911 | qeth_init_func_level(card); | 3896 | qeth_init_func_level(card); |
3912 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); | 3897 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); |
@@ -3990,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
3990 | struct qdio_buffer_element *element = *__element; | 3975 | struct qdio_buffer_element *element = *__element; |
3991 | int offset = *__offset; | 3976 | int offset = *__offset; |
3992 | struct sk_buff *skb = NULL; | 3977 | struct sk_buff *skb = NULL; |
3993 | int skb_len; | 3978 | int skb_len = 0; |
3994 | void *data_ptr; | 3979 | void *data_ptr; |
3995 | int data_len; | 3980 | int data_len; |
3996 | int headroom = 0; | 3981 | int headroom = 0; |
@@ -4009,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
4009 | *hdr = element->addr + offset; | 3994 | *hdr = element->addr + offset; |
4010 | 3995 | ||
4011 | offset += sizeof(struct qeth_hdr); | 3996 | offset += sizeof(struct qeth_hdr); |
4012 | if (card->options.layer2) { | 3997 | switch ((*hdr)->hdr.l2.id) { |
4013 | if (card->info.type == QETH_CARD_TYPE_OSN) { | 3998 | case QETH_HEADER_TYPE_LAYER2: |
4014 | skb_len = (*hdr)->hdr.osn.pdu_length; | 3999 | skb_len = (*hdr)->hdr.l2.pkt_length; |
4015 | headroom = sizeof(struct qeth_hdr); | 4000 | break; |
4016 | } else { | 4001 | case QETH_HEADER_TYPE_LAYER3: |
4017 | skb_len = (*hdr)->hdr.l2.pkt_length; | ||
4018 | } | ||
4019 | } else { | ||
4020 | skb_len = (*hdr)->hdr.l3.length; | 4002 | skb_len = (*hdr)->hdr.l3.length; |
4021 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || | 4003 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || |
4022 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) | 4004 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) |
4023 | headroom = TR_HLEN; | 4005 | headroom = TR_HLEN; |
4024 | else | 4006 | else |
4025 | headroom = ETH_HLEN; | 4007 | headroom = ETH_HLEN; |
4008 | break; | ||
4009 | case QETH_HEADER_TYPE_OSN: | ||
4010 | skb_len = (*hdr)->hdr.osn.pdu_length; | ||
4011 | headroom = sizeof(struct qeth_hdr); | ||
4012 | break; | ||
4013 | default: | ||
4014 | break; | ||
4026 | } | 4015 | } |
4027 | 4016 | ||
4028 | if (!skb_len) | 4017 | if (!skb_len) |
@@ -4177,6 +4166,33 @@ void qeth_core_free_discipline(struct qeth_card *card) | |||
4177 | card->discipline.ccwgdriver = NULL; | 4166 | card->discipline.ccwgdriver = NULL; |
4178 | } | 4167 | } |
4179 | 4168 | ||
4169 | static void qeth_determine_capabilities(struct qeth_card *card) | ||
4170 | { | ||
4171 | int rc; | ||
4172 | |||
4173 | QETH_DBF_TEXT(SETUP, 2, "detcapab"); | ||
4174 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
4175 | if (rc) { | ||
4176 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | ||
4177 | goto out; | ||
4178 | } | ||
4179 | |||
4180 | rc = qeth_get_unitaddr(card); | ||
4181 | if (rc) { | ||
4182 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
4183 | goto out_offline; | ||
4184 | } | ||
4185 | |||
4186 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
4187 | if (rc) | ||
4188 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | ||
4189 | |||
4190 | out_offline: | ||
4191 | ccw_device_set_offline(CARD_DDEV(card)); | ||
4192 | out: | ||
4193 | return; | ||
4194 | } | ||
4195 | |||
4180 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) | 4196 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) |
4181 | { | 4197 | { |
4182 | struct qeth_card *card; | 4198 | struct qeth_card *card; |
@@ -4242,6 +4258,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) | |||
4242 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); | 4258 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); |
4243 | list_add_tail(&card->list, &qeth_core_card_list.list); | 4259 | list_add_tail(&card->list, &qeth_core_card_list.list); |
4244 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); | 4260 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); |
4261 | |||
4262 | qeth_determine_capabilities(card); | ||
4245 | return 0; | 4263 | return 0; |
4246 | 4264 | ||
4247 | err_card: | 4265 | err_card: |
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 1ba51152f667..104a3351e02b 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes { | |||
156 | IPA_RC_IP_TABLE_FULL = 0x0002, | 156 | IPA_RC_IP_TABLE_FULL = 0x0002, |
157 | IPA_RC_UNKNOWN_ERROR = 0x0003, | 157 | IPA_RC_UNKNOWN_ERROR = 0x0003, |
158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, | 158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, |
159 | IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005, | ||
160 | IPA_RC_INVALID_FORMAT = 0x0006, | ||
159 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, | 161 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, |
160 | IPA_RC_DUP_IPV6_HOME = 0x0010, | 162 | IPA_RC_DUP_IPV6_HOME = 0x0010, |
161 | IPA_RC_UNREGISTERED_ADDR = 0x0011, | 163 | IPA_RC_UNREGISTERED_ADDR = 0x0011, |
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes { | |||
196 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, | 198 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, |
197 | IPA_RC_FFFF = 0xffff | 199 | IPA_RC_FFFF = 0xffff |
198 | }; | 200 | }; |
201 | /* for DELIP */ | ||
202 | #define IPA_RC_IP_ADDRESS_NOT_DEFINED IPA_RC_PRIMARY_ALREADY_DEFINED | ||
203 | /* for SET_DIAGNOSTIC_ASSIST */ | ||
204 | #define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL | ||
205 | #define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR | ||
199 | 206 | ||
200 | /* IPA function flags; each flag marks availability of respective function */ | 207 | /* IPA function flags; each flag marks availability of respective function */ |
201 | enum qeth_ipa_funcs { | 208 | enum qeth_ipa_funcs { |
@@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd { | |||
246 | IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, | 253 | IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, |
247 | IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, | 254 | IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, |
248 | IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, | 255 | IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, |
256 | IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L, | ||
249 | IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, | 257 | IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, |
250 | }; | 258 | }; |
251 | enum qeth_ipa_mac_ops { | 259 | enum qeth_ipa_mac_ops { |
@@ -424,6 +432,40 @@ struct qeth_create_destroy_address { | |||
424 | __u8 unique_id[8]; | 432 | __u8 unique_id[8]; |
425 | } __attribute__ ((packed)); | 433 | } __attribute__ ((packed)); |
426 | 434 | ||
435 | /* SET DIAGNOSTIC ASSIST IPA Command: *************************************/ | ||
436 | |||
437 | enum qeth_diags_cmds { | ||
438 | QETH_DIAGS_CMD_QUERY = 0x0001, | ||
439 | QETH_DIAGS_CMD_TRAP = 0x0002, | ||
440 | QETH_DIAGS_CMD_TRACE = 0x0004, | ||
441 | QETH_DIAGS_CMD_NOLOG = 0x0008, | ||
442 | QETH_DIAGS_CMD_DUMP = 0x0010, | ||
443 | }; | ||
444 | |||
445 | enum qeth_diags_trace_types { | ||
446 | QETH_DIAGS_TYPE_HIPERSOCKET = 0x02, | ||
447 | }; | ||
448 | |||
449 | enum qeth_diags_trace_cmds { | ||
450 | QETH_DIAGS_CMD_TRACE_ENABLE = 0x0001, | ||
451 | QETH_DIAGS_CMD_TRACE_DISABLE = 0x0002, | ||
452 | QETH_DIAGS_CMD_TRACE_MODIFY = 0x0004, | ||
453 | QETH_DIAGS_CMD_TRACE_REPLACE = 0x0008, | ||
454 | QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, | ||
455 | }; | ||
456 | |||
457 | struct qeth_ipacmd_diagass { | ||
458 | __u32 host_tod2; | ||
459 | __u32:32; | ||
460 | __u16 subcmd_len; | ||
461 | __u16:16; | ||
462 | __u32 subcmd; | ||
463 | __u8 type; | ||
464 | __u8 action; | ||
465 | __u16 options; | ||
466 | __u32:32; | ||
467 | } __attribute__ ((packed)); | ||
468 | |||
427 | /* Header for each IPA command */ | 469 | /* Header for each IPA command */ |
428 | struct qeth_ipacmd_hdr { | 470 | struct qeth_ipacmd_hdr { |
429 | __u8 command; | 471 | __u8 command; |
@@ -452,6 +494,7 @@ struct qeth_ipa_cmd { | |||
452 | struct qeth_create_destroy_address create_destroy_addr; | 494 | struct qeth_create_destroy_address create_destroy_addr; |
453 | struct qeth_ipacmd_setadpparms setadapterparms; | 495 | struct qeth_ipacmd_setadpparms setadapterparms; |
454 | struct qeth_set_routing setrtg; | 496 | struct qeth_set_routing setrtg; |
497 | struct qeth_ipacmd_diagass diagass; | ||
455 | } data; | 498 | } data; |
456 | } __attribute__ ((packed)); | 499 | } __attribute__ ((packed)); |
457 | 500 | ||
@@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes { | |||
469 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, | 512 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, |
470 | }; | 513 | }; |
471 | 514 | ||
472 | |||
473 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); | 515 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); |
474 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); | 516 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); |
475 | 517 | ||
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 9ff2b36fdc43..ac2239a4f133 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c | |||
@@ -118,7 +118,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
118 | { | 118 | { |
119 | struct qeth_card *card = dev_get_drvdata(dev); | 119 | struct qeth_card *card = dev_get_drvdata(dev); |
120 | char *tmp; | 120 | char *tmp; |
121 | unsigned int portno; | 121 | unsigned int portno, limit; |
122 | 122 | ||
123 | if (!card) | 123 | if (!card) |
124 | return -EINVAL; | 124 | return -EINVAL; |
@@ -128,9 +128,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
128 | return -EPERM; | 128 | return -EPERM; |
129 | 129 | ||
130 | portno = simple_strtoul(buf, &tmp, 16); | 130 | portno = simple_strtoul(buf, &tmp, 16); |
131 | if (portno > QETH_MAX_PORTNO) { | 131 | if (portno > QETH_MAX_PORTNO) |
132 | return -EINVAL; | ||
133 | limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); | ||
134 | if (portno > limit) | ||
132 | return -EINVAL; | 135 | return -EINVAL; |
133 | } | ||
134 | 136 | ||
135 | card->info.portno = portno; | 137 | card->info.portno = portno; |
136 | return count; | 138 | return count; |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 038299ae3feb..74ba388a159f 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -769,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | |||
769 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 769 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
770 | buffer = &card->qdio.in_q->bufs[index]; | 770 | buffer = &card->qdio.in_q->bufs[index]; |
771 | if (!(qdio_err && | 771 | if (!(qdio_err && |
772 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr"))) | 772 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, |
773 | "qinerr"))) | ||
773 | qeth_l2_process_inbound_buffer(card, buffer, index); | 774 | qeth_l2_process_inbound_buffer(card, buffer, index); |
774 | /* clear buffer and give back to hardware */ | 775 | /* clear buffer and give back to hardware */ |
775 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | 776 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); |
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 321988fa9f7d..8447d233d0b3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h | |||
@@ -13,6 +13,8 @@ | |||
13 | 13 | ||
14 | #include "qeth_core.h" | 14 | #include "qeth_core.h" |
15 | 15 | ||
16 | #define QETH_SNIFF_AVAIL 0x0008 | ||
17 | |||
16 | struct qeth_ipaddr { | 18 | struct qeth_ipaddr { |
17 | struct list_head entry; | 19 | struct list_head entry; |
18 | enum qeth_ip_types type; | 20 | enum qeth_ip_types type; |
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); |
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 3360b0941aa1..3f08b11274ae 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c | |||
@@ -319,6 +319,61 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev, | |||
319 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, | 319 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, |
320 | qeth_l3_dev_checksum_store); | 320 | qeth_l3_dev_checksum_store); |
321 | 321 | ||
322 | static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, | ||
323 | struct device_attribute *attr, char *buf) | ||
324 | { | ||
325 | struct qeth_card *card = dev_get_drvdata(dev); | ||
326 | |||
327 | if (!card) | ||
328 | return -EINVAL; | ||
329 | |||
330 | return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0); | ||
331 | } | ||
332 | |||
333 | static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, | ||
334 | struct device_attribute *attr, const char *buf, size_t count) | ||
335 | { | ||
336 | struct qeth_card *card = dev_get_drvdata(dev); | ||
337 | int ret; | ||
338 | unsigned long i; | ||
339 | |||
340 | if (!card) | ||
341 | return -EINVAL; | ||
342 | |||
343 | if (card->info.type != QETH_CARD_TYPE_IQD) | ||
344 | return -EPERM; | ||
345 | |||
346 | if ((card->state != CARD_STATE_DOWN) && | ||
347 | (card->state != CARD_STATE_RECOVER)) | ||
348 | return -EPERM; | ||
349 | |||
350 | ret = strict_strtoul(buf, 16, &i); | ||
351 | if (ret) | ||
352 | return -EINVAL; | ||
353 | switch (i) { | ||
354 | case 0: | ||
355 | card->options.sniffer = i; | ||
356 | break; | ||
357 | case 1: | ||
358 | ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
359 | if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) { | ||
360 | card->options.sniffer = i; | ||
361 | if (card->qdio.init_pool.buf_count != | ||
362 | QETH_IN_BUF_COUNT_MAX) | ||
363 | qeth_realloc_buffer_pool(card, | ||
364 | QETH_IN_BUF_COUNT_MAX); | ||
365 | break; | ||
366 | } else | ||
367 | return -EPERM; | ||
368 | default: /* fall through */ | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | return count; | ||
372 | } | ||
373 | |||
374 | static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, | ||
375 | qeth_l3_dev_sniffer_store); | ||
376 | |||
322 | static ssize_t qeth_l3_dev_large_send_show(struct device *dev, | 377 | static ssize_t qeth_l3_dev_large_send_show(struct device *dev, |
323 | struct device_attribute *attr, char *buf) | 378 | struct device_attribute *attr, char *buf) |
324 | { | 379 | { |
@@ -373,6 +428,7 @@ static struct attribute *qeth_l3_device_attrs[] = { | |||
373 | &dev_attr_broadcast_mode.attr, | 428 | &dev_attr_broadcast_mode.attr, |
374 | &dev_attr_canonical_macaddr.attr, | 429 | &dev_attr_canonical_macaddr.attr, |
375 | &dev_attr_checksumming.attr, | 430 | &dev_attr_checksumming.attr, |
431 | &dev_attr_sniffer.attr, | ||
376 | &dev_attr_large_send.attr, | 432 | &dev_attr_large_send.attr, |
377 | NULL, | 433 | NULL, |
378 | }; | 434 | }; |