mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Get rid of the following GCC8 compile warning by using different buffers
for input/output:
qethqoat.c: In function ‘ebctoasc’:
qethqoat.c:51:30: warning: passing argument 2 to restrict-qualified
parameter aliases with argument 4 [-Wrestrict]
iconv(l_iconv_ebcdic_ascii, &inout, &len, &inout, &len);
^~~~~~ ~~~~~~
qethqoat.c:51:38: warning: passing argument 3 to restrict-qualified
parameter aliases with argument 5 [-Wrestrict]
iconv(l_iconv_ebcdic_ascii, &inout, &len, &inout, &len);
^~~~ ~~~~
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
655 lines
16 KiB
C
655 lines
16 KiB
C
/*
|
|
* qethqoat - Query the OSA address table and display physical and logical
|
|
* device information
|
|
*
|
|
* Copyright IBM Corp. 2012, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <iconv.h>
|
|
#include <net/if.h>
|
|
#include <netdb.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/util_libc.h"
|
|
#include "lib/zt_common.h"
|
|
#include "qethqoat.h"
|
|
|
|
static iconv_t l_iconv_ebcdic_ascii;
|
|
|
|
static void hex_dump(char *buf, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (i && !(i % 16))
|
|
printf("\n");
|
|
printf("%02x ", *(buf + i));
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static int mac_is_zero(__u8 *mac)
|
|
{
|
|
return !(mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]);
|
|
}
|
|
|
|
static void ebctoasc(char *in, char *out, size_t size)
|
|
{
|
|
size_t size_out = size;
|
|
size_t size_in = size;
|
|
size_t rc;
|
|
|
|
rc = iconv(l_iconv_ebcdic_ascii, &in, &size_in, &out, &size_out);
|
|
if (rc == (size_t) -1)
|
|
fprintf(stderr, "Code page translation EBCDIC-ASCII failed\n");
|
|
}
|
|
|
|
static void print_version()
|
|
{
|
|
printf("qethqoat: Tool to query the OSA address table version %s\n",
|
|
RELEASE_STRING);
|
|
printf("Copyright IBM Corp. 2012, 2017\n");
|
|
}
|
|
|
|
static void print_ip4(struct qeth_qoat_des_ip4 *ip4, int hdr)
|
|
{
|
|
struct in_addr ia;
|
|
ia.s_addr = ip4->ip4_address;
|
|
if (hdr)
|
|
printf("\n%-39s %s\n%-39s %s\n", "IPv4 Address:",
|
|
"IPA Flags:", "-------------", "----------");
|
|
printf("%-39s 0x%08x\n", inet_ntoa(ia), ip4->flags);
|
|
}
|
|
|
|
static void print_ip4mc(struct qeth_qoat_des_ip4mc *ip4mc, int hdr)
|
|
{
|
|
struct in_addr ia;
|
|
ia.s_addr = ip4mc->ip4_mc_address;
|
|
if (hdr)
|
|
printf("\n%-39s %s\n%-39s %s\n", "IPv4 Multicast Address:",
|
|
"MAC Address:", "-----------------------", "------------");
|
|
printf("%-39s %02x:%02x:%02x:%02x:%02x:%02x\n", inet_ntoa(ia),
|
|
ip4mc->ip4_mc_mac[0], ip4mc->ip4_mc_mac[1],
|
|
ip4mc->ip4_mc_mac[2], ip4mc->ip4_mc_mac[3],
|
|
ip4mc->ip4_mc_mac[4], ip4mc->ip4_mc_mac[5]);
|
|
}
|
|
|
|
static void print_ip6(struct qeth_qoat_des_ip6 *ip6, int hdr)
|
|
{
|
|
char tmp[128];
|
|
struct in6_addr ia;
|
|
|
|
memcpy(&ia.s6_addr, &ip6->ip6_address, 16);
|
|
inet_ntop(AF_INET6, &ia, tmp, 128);
|
|
if (hdr)
|
|
printf("\n%-39s %s\n%-39s %s\n", "IPv6 Address:",
|
|
"IPA Flags:", "-------------", "----------");
|
|
printf("%-39s 0x%08x\n", tmp, ip6->flags);
|
|
}
|
|
|
|
static void print_ip6mc(struct qeth_qoat_des_ip6mc *ip6mc, int hdr)
|
|
{
|
|
char tmp[128];
|
|
struct in6_addr ia;
|
|
|
|
memcpy(&ia.s6_addr, &ip6mc->ip6_mc_address, 16);
|
|
inet_ntop(AF_INET6, &ia, tmp, 128);
|
|
if (hdr)
|
|
printf("\n%-39s %s\n%-39s %s\n", "IPv6 Multicast Address:",
|
|
"MAC Address:", "-----------------------", "------------");
|
|
printf("%-39s %02x:%02x:%02x:%02x:%02x:%02x\n", tmp,
|
|
ip6mc->ip6_mc_mac[0], ip6mc->ip6_mc_mac[1],
|
|
ip6mc->ip6_mc_mac[2], ip6mc->ip6_mc_mac[3],
|
|
ip6mc->ip6_mc_mac[4], ip6mc->ip6_mc_mac[5]);
|
|
}
|
|
|
|
static void print_vmac(struct qeth_qoat_des_vmac *vmac, int hdr)
|
|
{
|
|
if (hdr)
|
|
printf("\nvmac\n----\n");
|
|
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
vmac->vmac[0], vmac->vmac[1], vmac->vmac[2],
|
|
vmac->vmac[3], vmac->vmac[4], vmac->vmac[5]);
|
|
}
|
|
|
|
static void print_vlan(struct qeth_qoat_des_vlan *vlan, int hdr)
|
|
{
|
|
if (hdr)
|
|
printf("\nvlan\n----\n");
|
|
printf("%d\n", vlan->vlanid);
|
|
}
|
|
|
|
static void print_gmac(struct qeth_qoat_des_gmac *gmac, int hdr)
|
|
{
|
|
if (hdr)
|
|
printf("\ngmac\n----\n");
|
|
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
gmac->gmac[0], gmac->gmac[1], gmac->gmac[2],
|
|
gmac->gmac[3], gmac->gmac[4], gmac->gmac[5]);
|
|
}
|
|
|
|
static void print_aiq(struct qeth_qoat_des_aiq *aiq, int hdr)
|
|
{
|
|
if (hdr)
|
|
printf("\naiq routing variables\n---------------------\n");
|
|
printf("0x%x %d %d\n", aiq->protocol, aiq->src_port, aiq->des_port);
|
|
}
|
|
|
|
static void print_physical(struct qeth_qoat_physical *phdr)
|
|
{
|
|
char *speed, *media, *jumbo, *osagen, *chpid_type;
|
|
char tmp[128];
|
|
|
|
printf("PCHID: 0x%04x\n", phdr->pchid);
|
|
|
|
printf("CHPID: 0x%02x\n", phdr->chpid);
|
|
|
|
printf("Manufacturer MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
phdr->physical_mac[0], phdr->physical_mac[1],
|
|
phdr->physical_mac[2], phdr->physical_mac[3],
|
|
phdr->physical_mac[4], phdr->physical_mac[5]);
|
|
|
|
printf("Configured MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
phdr->logical_mac[0], phdr->logical_mac[1],
|
|
phdr->logical_mac[2], phdr->logical_mac[3],
|
|
phdr->logical_mac[4], phdr->logical_mac[5]);
|
|
|
|
printf("Data device sub-channel address: 0x%04x\n",
|
|
phdr->data_sub_channel);
|
|
|
|
printf("CULA: 0x%02x\n", phdr->cula);
|
|
|
|
printf("Unit address: 0x%02x\n", phdr->unit_address);
|
|
|
|
printf("Physical port number: %d\n", phdr->physical_port);
|
|
|
|
printf("Number of output queues: %d\n", phdr->nr_out_queues);
|
|
|
|
printf("Number of input queues: %d\n", phdr->nr_in_queues);
|
|
|
|
printf("Number of active input queues: %d\n",
|
|
phdr->nr_active_in_queues);
|
|
|
|
switch (phdr->interface_flags_chpid_type) {
|
|
case OAT_IFF_CHPID_TYPE_OSD:
|
|
chpid_type = "OSD";
|
|
break;
|
|
case OAT_IFF_CHPID_TYPE_OSX:
|
|
chpid_type = "OSX";
|
|
break;
|
|
case OAT_IFF_CHPID_TYPE_OSM:
|
|
chpid_type = "OSM";
|
|
break;
|
|
default:
|
|
sprintf(tmp, "unknown (0x%x)",
|
|
phdr->interface_flags_chpid_type);
|
|
chpid_type = tmp;
|
|
}
|
|
printf("CHPID Type: %s\n", chpid_type);
|
|
printf("Interface flags: 0x%08x\n", phdr->interface_flags);
|
|
|
|
switch (phdr->osa_gen) {
|
|
case OAT_OSA_GEN_OSAE3:
|
|
osagen = "OSA-Express3";
|
|
break;
|
|
case OAT_OSA_GEN_OSAE4S:
|
|
osagen = "OSA-Express4S";
|
|
break;
|
|
case OAT_OSA_GEN_OSAE5S:
|
|
osagen = "OSA-Express5S";
|
|
break;
|
|
case OAT_OSA_GEN_OSAE6S:
|
|
osagen = "OSA-Express6S";
|
|
break;
|
|
case OAT_OSA_GEN_OSAE7S:
|
|
osagen = "OSA-Express7S";
|
|
break;
|
|
default:
|
|
sprintf(tmp, "unknown (0x%x)", phdr->osa_gen);
|
|
osagen = tmp;
|
|
}
|
|
printf("OSA Generation: %s\n", osagen);
|
|
|
|
switch (phdr->port_speed) {
|
|
case OAT_PORT_SPEED_10mbs_half:
|
|
speed = "10 Mb/s / half duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_10mbs_full:
|
|
speed = "10 Mb/s / full duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_100mbs_half:
|
|
speed = "100 Mb/s / half duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_100mbs_full:
|
|
speed = "100 Mb/s / full duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_1000mbs_half:
|
|
speed = "1000 Mb/s / half duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_1000mbs_full:
|
|
speed = "1000 Mb/s / full duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_NA:
|
|
speed = "NA / NA";
|
|
break;
|
|
case OAT_PORT_SPEED_10gbs_full:
|
|
speed = "10 Gb/s / full duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_25gbs_full:
|
|
speed = "25 Gb/s / full duplex";
|
|
break;
|
|
case OAT_PORT_SPEED_UNKNOWN:
|
|
speed = "unknown / unknown";
|
|
break;
|
|
default:
|
|
sprintf(tmp, "(0x%x) / (0x%x)", phdr->port_speed,
|
|
phdr->port_speed);
|
|
speed = tmp;
|
|
}
|
|
printf("Port speed/mode: %s\n", speed);
|
|
|
|
switch (phdr->port_media) {
|
|
case OAT_PORT_MEDIA_COPPER:
|
|
media = "copper";
|
|
break;
|
|
case OAT_PORT_MEDIA_MULTI_MODE:
|
|
media = "multi mode (SR/SX)";
|
|
break;
|
|
case OAT_PORT_MEDIA_SINGLE_MODE:
|
|
media = "single mode (LR/LX)";
|
|
break;
|
|
default:
|
|
sprintf(tmp, "unknown (0x%x)", phdr->port_media);
|
|
media = tmp;
|
|
}
|
|
printf("Port media type: %s\n", media);
|
|
|
|
if (phdr->port_media_att & OAT_PORT_MEDIA_ATT_JUMBO)
|
|
jumbo = "yes";
|
|
else
|
|
jumbo = "no";
|
|
printf("Jumbo frames: %s\n", jumbo);
|
|
|
|
printf("Firmware: 0x%08x\n", phdr->firmware);
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
static void print_logical(struct qeth_qoat_logical *lhdr)
|
|
{
|
|
char prouter[] = "primary";
|
|
char srouter[] = "secondary";
|
|
char nrouter[] = "no";
|
|
char port_name[8];
|
|
char *router;
|
|
|
|
if (lhdr->ip4_primary_router)
|
|
router = prouter;
|
|
else if (lhdr->ip4_secondary_router)
|
|
router = srouter;
|
|
else
|
|
router = nrouter;
|
|
printf("IPv4 router: %s %s\n", router, lhdr->ip4_active_router ?
|
|
"active" : "");
|
|
|
|
if (lhdr->ip6_primary_router)
|
|
router = prouter;
|
|
else if (lhdr->ip6_secondary_router)
|
|
router = srouter;
|
|
else
|
|
router = nrouter;
|
|
printf("IPv6 router: %s %s\n", router, lhdr->ip6_active_router ?
|
|
"active" : "");
|
|
|
|
printf("IPv4 vmac router: %s\n", lhdr->ip4_vmac_router ? "yes" : "no");
|
|
printf("IPv6 vmac router: %s\n", lhdr->ip6_vmac_router ? "yes" : "no");
|
|
|
|
printf("Connection isolation: %s\n", lhdr->isolation_f ?
|
|
"active" : "not active");
|
|
|
|
printf("Connection isolation VEPA: %s\n", lhdr->isolation_vepa ?
|
|
"yes" : "no");
|
|
|
|
if (lhdr->ip4_global_vlan_active)
|
|
printf("IPv4 global vlan id: %d\n", lhdr->ip4_global_vlanid);
|
|
|
|
if (lhdr->ip4_vmac_active)
|
|
printf("IPv4 l3 vmac: %02x:%02x:%02x:%02x:%02x:%02x"
|
|
" %s generated\n",
|
|
lhdr->ip4_vmac[0], lhdr->ip4_vmac[1],
|
|
lhdr->ip4_vmac[2], lhdr->ip4_vmac[3],
|
|
lhdr->ip4_vmac[4], lhdr->ip4_vmac[4],
|
|
lhdr->ip4_vmac_source ? "OSA" : "Host");
|
|
|
|
if (lhdr->ip6_global_vlan_active)
|
|
printf("IPv6 global vlan id: %d\n", lhdr->ip6_global_vlanid);
|
|
|
|
if (lhdr->ip6_vmac_active)
|
|
printf("IPv6 l3 vmac: %02x:%02x:%02x:%02x:%02x:%02x"
|
|
" %s generated\n",
|
|
lhdr->ip6_vmac[0], lhdr->ip6_vmac[1],
|
|
lhdr->ip6_vmac[2], lhdr->ip6_vmac[3],
|
|
lhdr->ip6_vmac[4], lhdr->ip6_vmac[4],
|
|
lhdr->ip6_vmac_source ? "OSA" : "Host");
|
|
|
|
|
|
if (lhdr->port_name_f) {
|
|
ebctoasc((char *)lhdr->port_name, port_name, 8);
|
|
printf("Port name: %.8s\n", port_name);
|
|
}
|
|
|
|
printf("IPv4 assists enabled: 0x%08x\n", lhdr->ip4_ass_enabled);
|
|
printf("IPv6 assists enabled: 0x%08x\n", lhdr->ip6_ass_enabled);
|
|
printf("IPv4 outbound checksum enabled: 0x%08x\n",
|
|
lhdr->out_csum_enabled);
|
|
printf("IPv6 outbound checksum enabled: 0x%08x\n",
|
|
lhdr->out_csum_enabled6);
|
|
printf("IPv4 inbound checksum enabled: 0x%08x\n",
|
|
lhdr->in_csum_enabled);
|
|
printf("IPv6 inbound checksum enabled: 0x%08x\n",
|
|
lhdr->in_csum_enabled6);
|
|
|
|
if (lhdr->l2_vlanid)
|
|
printf("L2 vlan id: %d\n", lhdr->l2_vlanid);
|
|
|
|
if (!mac_is_zero(lhdr->l2_vmac))
|
|
printf("L2 vmac: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
lhdr->l2_vmac[0], lhdr->l2_vmac[1], lhdr->l2_vmac[2],
|
|
lhdr->l2_vmac[3], lhdr->l2_vmac[4], lhdr->l2_vmac[5]);
|
|
}
|
|
|
|
static void parse_descriptor(struct qeth_qoat_hdr *oat_hdr,
|
|
struct qeth_print_hdr *phdr, char *buf, int *processed)
|
|
{
|
|
int i;
|
|
char *ptr;
|
|
|
|
*processed += oat_hdr->len;
|
|
for (i = 0; i < oat_hdr->type.descriptor.reply_entry_count; i++) {
|
|
ptr = buf + *processed;
|
|
switch (oat_hdr->type.descriptor.des_type) {
|
|
case OAT_DES_TYPE_IP4:
|
|
print_ip4((struct qeth_qoat_des_ip4 *)ptr, phdr->ip4_h);
|
|
phdr->ip4_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_IP4MC:
|
|
print_ip4mc((struct qeth_qoat_des_ip4mc *)ptr,
|
|
phdr->ip4mc_h);
|
|
phdr->ip4mc_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_IP6:
|
|
print_ip6((struct qeth_qoat_des_ip6 *)ptr, phdr->ip6_h);
|
|
phdr->ip6_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_IP6MC:
|
|
print_ip6mc((struct qeth_qoat_des_ip6mc *)ptr,
|
|
phdr->ip6mc_h);
|
|
phdr->ip6mc_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_VMAC:
|
|
print_vmac((struct qeth_qoat_des_vmac *)ptr,
|
|
phdr->vmac_h);
|
|
phdr->vmac_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_VLAN:
|
|
print_vlan((struct qeth_qoat_des_vlan *)ptr,
|
|
phdr->vlan_h);
|
|
phdr->vlan_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_GMAC:
|
|
print_gmac((struct qeth_qoat_des_gmac *)ptr,
|
|
phdr->gmac_h);
|
|
phdr->gmac_h = 0;
|
|
break;
|
|
case OAT_DES_TYPE_AIQ:
|
|
print_aiq((struct qeth_qoat_des_aiq *)ptr,
|
|
phdr->aiq_h);
|
|
phdr->aiq_h = 0;
|
|
break;
|
|
default:
|
|
printf("Unknown descriptor (0x%x)\n",
|
|
oat_hdr->type.descriptor.des_type);
|
|
hex_dump(ptr,
|
|
oat_hdr->type.descriptor.reply_entry_len);
|
|
}
|
|
*processed += oat_hdr->type.descriptor.reply_entry_len;
|
|
}
|
|
}
|
|
|
|
static int print_IPA_error(int rc)
|
|
{
|
|
switch (rc) {
|
|
case 0x0:
|
|
break;
|
|
case 0x4:
|
|
fprintf(stderr, "Error: Command not supported\n");
|
|
break;
|
|
case 0x8:
|
|
fprintf(stderr,
|
|
"Error: Invalid/unsupported sub_command/scope\n");
|
|
break;
|
|
case 0x10:
|
|
fprintf(stderr, "Error: No active data connection\n");
|
|
break;
|
|
case 0x14:
|
|
fprintf(stderr, "Error: OSA temporary resource shortage\n");
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void parse_data(char *buf, int len)
|
|
{
|
|
int buffer_processed;
|
|
int frame_processed;
|
|
struct qeth_qoat_ipa_reply *ipa_hdr;
|
|
struct qeth_qoat_hdr *oat_hdr;
|
|
struct qeth_print_hdr phdr = {1, 1, 1, 1, 1, 1, 1, 1};
|
|
|
|
buffer_processed = 0;
|
|
do {
|
|
frame_processed = 0;
|
|
ipa_hdr = (struct qeth_qoat_ipa_reply *)
|
|
(buf + buffer_processed);
|
|
if (print_IPA_error(ipa_hdr->rc))
|
|
fprintf(stderr, "OSA reported error code 0x%x\n",
|
|
ipa_hdr->rc);
|
|
|
|
if (ipa_hdr->subcommand == 0) {
|
|
printf("Supported Scope mask: 0x%08x\n",
|
|
ipa_hdr->supported_scope);
|
|
printf("Supported Descriptor hdr types: 0x%08x\n",
|
|
ipa_hdr->supported_descriptor);
|
|
}
|
|
frame_processed += sizeof(struct qeth_qoat_ipa_reply);
|
|
|
|
if (frame_processed >= ipa_hdr->len)
|
|
break;
|
|
|
|
do {
|
|
oat_hdr = (struct qeth_qoat_hdr *)
|
|
(buf + buffer_processed + frame_processed);
|
|
switch (oat_hdr->hdr_type) {
|
|
case OAT_HDR_TYPE_PHYSICAL:
|
|
print_physical(&oat_hdr->type.physical);
|
|
frame_processed += oat_hdr->len;
|
|
break;
|
|
case OAT_HDR_TYPE_LOGICAL:
|
|
print_logical(&oat_hdr->type.logical);
|
|
frame_processed += oat_hdr->len;
|
|
break;
|
|
case OAT_HDR_TYPE_DESCRIPTOR:
|
|
parse_descriptor(oat_hdr, &phdr,
|
|
buf + buffer_processed,
|
|
&frame_processed);
|
|
break;
|
|
default:
|
|
printf("Unknown oat hdr (0x%x)\n",
|
|
oat_hdr->hdr_type);
|
|
return;
|
|
}
|
|
} while (frame_processed < ipa_hdr->len);
|
|
|
|
buffer_processed += ipa_hdr->len;
|
|
} while (buffer_processed < len);
|
|
}
|
|
|
|
static void printusage()
|
|
{
|
|
fprintf(stdout, "Usage: qethqoat [-h] [-v]\n"
|
|
" qethqoat [-r] [-s scope] interface\n"
|
|
" qethqoat -f file\n\n"
|
|
"Use qethqoat to query the OSA address table and display "
|
|
"physical and logical\ndevice information\n\n"
|
|
"-h, --help Displays the help information.\n"
|
|
"-r, --raw Writes raw data to stdout.\n"
|
|
"-f, --file Reads input from file.\n"
|
|
"-v, --version Prints the version number.\n"
|
|
"-s, --scope Defines the scope of the query.\n"
|
|
"\t 0 Query the level of the OSA address table\n"
|
|
"\t 1 Interface (default)\n"
|
|
);
|
|
}
|
|
|
|
static const struct option qethqoat_opts[] = {
|
|
{ "help", 0, 0, 'h'},
|
|
{ "raw", 0, 0, 'r'},
|
|
{ "file", 1, 0, 'f'},
|
|
{ "version", 0, 0, 'v'},
|
|
{ "scope", 1, 0, 's'},
|
|
{ 0, 0, 0, 0}
|
|
};
|
|
|
|
static const char qethqoat_opts_str[] = "vhrf:s:";
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct qoat_opts opts;
|
|
int sd, c, rc, index;
|
|
struct ifreq ifr;
|
|
struct qeth_query_oat_data oat_data;
|
|
size_t datalen = 131072;
|
|
|
|
opts.raw = 0;
|
|
opts.scope = 1;
|
|
opts.file = NULL;
|
|
opts.ifname = NULL;
|
|
|
|
while ((c = getopt_long(argc, argv, qethqoat_opts_str, qethqoat_opts,
|
|
&index)) != -1) {
|
|
switch (c) {
|
|
case 'h':
|
|
printusage();
|
|
return 0;
|
|
case 'r':
|
|
opts.raw = 1;
|
|
break;
|
|
case 'f':
|
|
opts.file = optarg;
|
|
break;
|
|
case 's':
|
|
opts.scope = atoi(optarg);
|
|
break;
|
|
case 'v':
|
|
print_version();
|
|
return 0;
|
|
default:
|
|
printusage();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (optind == argc) {
|
|
if (!opts.file) { /* No -f file, interface name needed */
|
|
printusage();
|
|
return 1;
|
|
}
|
|
} else {
|
|
if (opts.file) { /* Have -f file, no interface name allowed */
|
|
printusage();
|
|
return 1;
|
|
}
|
|
opts.ifname = argv[optind];
|
|
if (strlen(opts.ifname) >= IFNAMSIZ) {
|
|
fprintf(stderr, "qethqoat: Interface name too long\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
oat_data.command = 0;
|
|
oat_data.ptr = (__u64)(unsigned long)malloc(datalen);
|
|
if (!oat_data.ptr) {
|
|
perror("qethqoat");
|
|
return 1;
|
|
}
|
|
oat_data.buffer_len = datalen;
|
|
oat_data.response_len = 0;
|
|
|
|
if (opts.file) {
|
|
FILE *rf = fopen(opts.file, "r");
|
|
if (!rf) {
|
|
perror("qethqoat");
|
|
free((void *)(unsigned long)oat_data.ptr);
|
|
return 1;
|
|
}
|
|
oat_data.response_len = fread(
|
|
(char *)(unsigned long)oat_data.ptr,
|
|
sizeof(char), oat_data.buffer_len, rf);
|
|
fclose(rf);
|
|
goto parse;
|
|
}
|
|
|
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sd < 0) {
|
|
perror("qethqoat");
|
|
free((void *)(unsigned long)oat_data.ptr);
|
|
return 1;
|
|
}
|
|
|
|
util_strlcpy(ifr.ifr_name, opts.ifname, IFNAMSIZ);
|
|
oat_data.command = opts.scope;
|
|
ifr.ifr_ifru.ifru_data = (void *)&oat_data;
|
|
|
|
rc = ioctl(sd, SIOC_QETH_QUERY_OAT, &ifr);
|
|
if (rc) {
|
|
if (print_IPA_error(rc))
|
|
perror("qethqoat");
|
|
close(sd);
|
|
free((void *)(unsigned long)oat_data.ptr);
|
|
return 1;
|
|
}
|
|
close(sd);
|
|
parse:
|
|
if (opts.raw) {
|
|
fwrite((char *)(unsigned long)oat_data.ptr,
|
|
sizeof(char), oat_data.response_len, stdout);
|
|
} else {
|
|
l_iconv_ebcdic_ascii = iconv_open("ISO-8859-1", "EBCDIC-US");
|
|
if (l_iconv_ebcdic_ascii == (iconv_t) -1) {
|
|
perror("qethqoat");
|
|
free((void *)(unsigned long)oat_data.ptr);
|
|
return 1;
|
|
}
|
|
parse_data((char *)(unsigned long)oat_data.ptr,
|
|
oat_data.response_len);
|
|
}
|
|
free((void *)(unsigned long)oat_data.ptr);
|
|
return 0;
|
|
}
|