aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net
diff options
context:
space:
mode:
authorEinar Lueck <elelueck@de.ibm.com>2010-12-07 21:57:58 -0500
committerDavid S. Miller <davem@davemloft.net>2010-12-10 17:28:47 -0500
commitd0ddf30fdd2b98fb547ffa33bb79a7a96ef8d7dd (patch)
treed4f714f2d40dd78241d4351aa4dffab5f6e364ed /drivers/s390/net
parentc07224005dd3fe746246acadc9be652a588a4d7f (diff)
qeth: support ipv6 query arp cache for HiperSockets
Function qeth_l3_arp_query now queries for IPv6 addresses, too, if QETH_QARP_WITH_IPV6 is passed as parameter to the ioctl. HiperSockets and GuestLAN in HiperSockets mode provide corresponding entries. Signed-off-by: Einar Lueck <elelueck@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')
-rw-r--r--drivers/s390/net/qeth_core_mpc.h2
-rw-r--r--drivers/s390/net/qeth_l3_main.c215
2 files changed, 144 insertions, 73 deletions
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index e37dd8c4bf4e..07d588867b57 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -333,7 +333,7 @@ struct qeth_arp_query_data {
333 __u16 request_bits; 333 __u16 request_bits;
334 __u16 reply_bits; 334 __u16 reply_bits;
335 __u32 no_entries; 335 __u32 no_entries;
336 char data; 336 char data; /* only for replies */
337} __attribute__((packed)); 337} __attribute__((packed));
338 338
339/* used as parameter for arp_query reply */ 339/* used as parameter for arp_query reply */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index a1abb37db000..a7590551e574 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -30,6 +30,7 @@
30 30
31#include "qeth_l3.h" 31#include "qeth_l3.h"
32 32
33
33static int qeth_l3_set_offline(struct ccwgroup_device *); 34static int qeth_l3_set_offline(struct ccwgroup_device *);
34static int qeth_l3_recover(void *); 35static int qeth_l3_recover(void *);
35static int qeth_l3_stop(struct net_device *); 36static int qeth_l3_stop(struct net_device *);
@@ -2455,22 +2456,46 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
2455 return rc; 2456 return rc;
2456} 2457}
2457 2458
2458static void qeth_l3_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, 2459static __u32 get_arp_entry_size(struct qeth_card *card,
2459 struct qeth_arp_query_data *qdata, int entry_size, 2460 struct qeth_arp_query_data *qdata,
2460 int uentry_size) 2461 struct qeth_arp_entrytype *type, __u8 strip_entries)
2461{ 2462{
2462 char *entry_ptr; 2463 __u32 rc;
2463 char *uentry_ptr; 2464 __u8 is_hsi;
2464 int i;
2465 2465
2466 entry_ptr = (char *)&qdata->data; 2466 is_hsi = qdata->reply_bits == 5;
2467 uentry_ptr = (char *)(qinfo->udata + qinfo->udata_offset); 2467 if (type->ip == QETHARP_IP_ADDR_V4) {
2468 for (i = 0; i < qdata->no_entries; ++i) { 2468 QETH_CARD_TEXT(card, 4, "arpev4");
2469 /* strip off 32 bytes "media specific information" */ 2469 if (strip_entries) {
2470 memcpy(uentry_ptr, (entry_ptr + 32), entry_size - 32); 2470 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) :
2471 entry_ptr += entry_size; 2471 sizeof(struct qeth_arp_qi_entry7_short);
2472 uentry_ptr += uentry_size; 2472 } else {
2473 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) :
2474 sizeof(struct qeth_arp_qi_entry7);
2475 }
2476 } else if (type->ip == QETHARP_IP_ADDR_V6) {
2477 QETH_CARD_TEXT(card, 4, "arpev6");
2478 if (strip_entries) {
2479 rc = is_hsi ?
2480 sizeof(struct qeth_arp_qi_entry5_short_ipv6) :
2481 sizeof(struct qeth_arp_qi_entry7_short_ipv6);
2482 } else {
2483 rc = is_hsi ?
2484 sizeof(struct qeth_arp_qi_entry5_ipv6) :
2485 sizeof(struct qeth_arp_qi_entry7_ipv6);
2486 }
2487 } else {
2488 QETH_CARD_TEXT(card, 4, "arpinv");
2489 rc = 0;
2473 } 2490 }
2491
2492 return rc;
2493}
2494
2495static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot)
2496{
2497 return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) ||
2498 (type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6);
2474} 2499}
2475 2500
2476static int qeth_l3_arp_query_cb(struct qeth_card *card, 2501static int qeth_l3_arp_query_cb(struct qeth_card *card,
@@ -2479,72 +2504,77 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
2479 struct qeth_ipa_cmd *cmd; 2504 struct qeth_ipa_cmd *cmd;
2480 struct qeth_arp_query_data *qdata; 2505 struct qeth_arp_query_data *qdata;
2481 struct qeth_arp_query_info *qinfo; 2506 struct qeth_arp_query_info *qinfo;
2482 int entry_size;
2483 int uentry_size;
2484 int i; 2507 int i;
2508 int e;
2509 int entrybytes_done;
2510 int stripped_bytes;
2511 __u8 do_strip_entries;
2485 2512
2486 QETH_CARD_TEXT(card, 4, "arpquecb"); 2513 QETH_CARD_TEXT(card, 3, "arpquecb");
2487 2514
2488 qinfo = (struct qeth_arp_query_info *) reply->param; 2515 qinfo = (struct qeth_arp_query_info *) reply->param;
2489 cmd = (struct qeth_ipa_cmd *) data; 2516 cmd = (struct qeth_ipa_cmd *) data;
2517 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version);
2490 if (cmd->hdr.return_code) { 2518 if (cmd->hdr.return_code) {
2491 QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code); 2519 QETH_CARD_TEXT(card, 4, "arpcberr");
2520 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
2492 return 0; 2521 return 0;
2493 } 2522 }
2494 if (cmd->data.setassparms.hdr.return_code) { 2523 if (cmd->data.setassparms.hdr.return_code) {
2495 cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; 2524 cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
2496 QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code); 2525 QETH_CARD_TEXT(card, 4, "setaperr");
2526 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
2497 return 0; 2527 return 0;
2498 } 2528 }
2499 qdata = &cmd->data.setassparms.data.query_arp; 2529 qdata = &cmd->data.setassparms.data.query_arp;
2500 switch (qdata->reply_bits) {
2501 case 5:
2502 uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry5);
2503 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
2504 uentry_size = sizeof(struct qeth_arp_qi_entry5_short);
2505 break;
2506 case 7:
2507 /* fall through to default */
2508 default:
2509 /* tr is the same as eth -> entry7 */
2510 uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry7);
2511 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
2512 uentry_size = sizeof(struct qeth_arp_qi_entry7_short);
2513 break;
2514 }
2515 /* check if there is enough room in userspace */
2516 if ((qinfo->udata_len - qinfo->udata_offset) <
2517 qdata->no_entries * uentry_size){
2518 QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
2519 cmd->hdr.return_code = -ENOMEM;
2520 goto out_error;
2521 }
2522 QETH_CARD_TEXT_(card, 4, "anore%i",
2523 cmd->data.setassparms.hdr.number_of_replies);
2524 QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
2525 QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries); 2530 QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
2526 2531
2527 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) { 2532 do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0;
2528 /* strip off "media specific information" */ 2533 stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0;
2529 qeth_l3_copy_arp_entries_stripped(qinfo, qdata, entry_size, 2534 entrybytes_done = 0;
2530 uentry_size); 2535 for (e = 0; e < qdata->no_entries; ++e) {
2531 } else 2536 char *cur_entry;
2532 /*copy entries to user buffer*/ 2537 __u32 esize;
2533 memcpy(qinfo->udata + qinfo->udata_offset, 2538 struct qeth_arp_entrytype *etype;
2534 (char *)&qdata->data, qdata->no_entries*uentry_size); 2539
2540 cur_entry = &qdata->data + entrybytes_done;
2541 etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type;
2542 if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) {
2543 QETH_CARD_TEXT(card, 4, "pmis");
2544 QETH_CARD_TEXT_(card, 4, "%i", etype->ip);
2545 break;
2546 }
2547 esize = get_arp_entry_size(card, qdata, etype,
2548 do_strip_entries);
2549 QETH_CARD_TEXT_(card, 5, "esz%i", esize);
2550 if (!esize)
2551 break;
2552
2553 if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
2554 QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
2555 cmd->hdr.return_code = -ENOMEM;
2556 goto out_error;
2557 }
2535 2558
2536 qinfo->no_entries += qdata->no_entries; 2559 memcpy(qinfo->udata + qinfo->udata_offset,
2537 qinfo->udata_offset += (qdata->no_entries*uentry_size); 2560 &qdata->data + entrybytes_done + stripped_bytes,
2561 esize);
2562 entrybytes_done += esize + stripped_bytes;
2563 qinfo->udata_offset += esize;
2564 ++qinfo->no_entries;
2565 }
2538 /* check if all replies received ... */ 2566 /* check if all replies received ... */
2539 if (cmd->data.setassparms.hdr.seq_no < 2567 if (cmd->data.setassparms.hdr.seq_no <
2540 cmd->data.setassparms.hdr.number_of_replies) 2568 cmd->data.setassparms.hdr.number_of_replies)
2541 return 1; 2569 return 1;
2570 QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries);
2542 memcpy(qinfo->udata, &qinfo->no_entries, 4); 2571 memcpy(qinfo->udata, &qinfo->no_entries, 4);
2543 /* keep STRIP_ENTRIES flag so the user program can distinguish 2572 /* keep STRIP_ENTRIES flag so the user program can distinguish
2544 * stripped entries from normal ones */ 2573 * stripped entries from normal ones */
2545 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) 2574 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
2546 qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES; 2575 qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;
2547 memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2); 2576 memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
2577 QETH_CARD_TEXT_(card, 4, "rc%i", 0);
2548 return 0; 2578 return 0;
2549out_error: 2579out_error:
2550 i = 0; 2580 i = 0;
@@ -2567,45 +2597,86 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card,
2567 reply_cb, reply_param); 2597 reply_cb, reply_param);
2568} 2598}
2569 2599
2570static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) 2600static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
2601 enum qeth_prot_versions prot,
2602 struct qeth_arp_query_info *qinfo)
2571{ 2603{
2572 struct qeth_cmd_buffer *iob; 2604 struct qeth_cmd_buffer *iob;
2573 struct qeth_arp_query_info qinfo = {0, }; 2605 struct qeth_ipa_cmd *cmd;
2574 int tmp; 2606 int tmp;
2575 int rc; 2607 int rc;
2576 2608
2609 QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
2610
2611 iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
2612 IPA_CMD_ASS_ARP_QUERY_INFO,
2613 sizeof(struct qeth_arp_query_data) - sizeof(char),
2614 prot);
2615 cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
2616 cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
2617 cmd->data.setassparms.data.query_arp.reply_bits = 0;
2618 cmd->data.setassparms.data.query_arp.no_entries = 0;
2619 rc = qeth_l3_send_ipa_arp_cmd(card, iob,
2620 QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
2621 qeth_l3_arp_query_cb, (void *)qinfo);
2622 if (rc) {
2623 tmp = rc;
2624 QETH_DBF_MESSAGE(2,
2625 "Error while querying ARP cache on %s: %s "
2626 "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
2627 qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
2628 }
2629
2630 return rc;
2631}
2632
2633static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
2634{
2635 struct qeth_arp_query_info qinfo = {0, };
2636 int rc;
2637
2577 QETH_CARD_TEXT(card, 3, "arpquery"); 2638 QETH_CARD_TEXT(card, 3, "arpquery");
2578 2639
2579 if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ 2640 if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
2580 IPA_ARP_PROCESSING)) { 2641 IPA_ARP_PROCESSING)) {
2581 return -EOPNOTSUPP; 2642 QETH_CARD_TEXT(card, 3, "arpqnsup");
2643 rc = -EOPNOTSUPP;
2644 goto out;
2582 } 2645 }
2583 /* get size of userspace buffer and mask_bits -> 6 bytes */ 2646 /* get size of userspace buffer and mask_bits -> 6 bytes */
2584 if (copy_from_user(&qinfo, udata, 6)) 2647 if (copy_from_user(&qinfo, udata, 6)) {
2585 return -EFAULT; 2648 rc = -EFAULT;
2649 goto out;
2650 }
2586 qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL); 2651 qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
2587 if (!qinfo.udata) 2652 if (!qinfo.udata) {
2588 return -ENOMEM; 2653 rc = -ENOMEM;
2654 goto out;
2655 }
2589 qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET; 2656 qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
2590 iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING, 2657 rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo);
2591 IPA_CMD_ASS_ARP_QUERY_INFO,
2592 sizeof(int), QETH_PROT_IPV4);
2593
2594 rc = qeth_l3_send_ipa_arp_cmd(card, iob,
2595 QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
2596 qeth_l3_arp_query_cb, (void *)&qinfo);
2597 if (rc) { 2658 if (rc) {
2598 tmp = rc;
2599 QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s "
2600 "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
2601 qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
2602 if (copy_to_user(udata, qinfo.udata, 4)) 2659 if (copy_to_user(udata, qinfo.udata, 4))
2603 rc = -EFAULT; 2660 rc = -EFAULT;
2661 goto free_and_out;
2604 } else { 2662 } else {
2605 if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) 2663#ifdef CONFIG_QETH_IPV6
2664 if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
2665 /* fails in case of GuestLAN QDIO mode */
2666 qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6,
2667 &qinfo);
2668 }
2669#endif
2670 if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
2671 QETH_CARD_TEXT(card, 4, "qactf");
2606 rc = -EFAULT; 2672 rc = -EFAULT;
2673 goto free_and_out;
2674 }
2675 QETH_CARD_TEXT_(card, 4, "qacts");
2607 } 2676 }
2677free_and_out:
2608 kfree(qinfo.udata); 2678 kfree(qinfo.udata);
2679out:
2609 return rc; 2680 return rc;
2610} 2681}
2611 2682