|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (c) 2015, QLogic Corporation
|
|
Packit |
eace71 |
* All rights reserved.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
eace71 |
* modification, are permitted provided that the following conditions
|
|
Packit |
eace71 |
* are met:
|
|
Packit |
eace71 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
eace71 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
eace71 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
eace71 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
eace71 |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
eace71 |
* 3. All advertising materials mentioning features or use of this software
|
|
Packit |
eace71 |
* must display the following acknowledgement:
|
|
Packit |
eace71 |
* This product includes software developed by Adam Dunkels.
|
|
Packit |
eace71 |
* 4. The name of the author may not be used to endorse or promote
|
|
Packit |
eace71 |
* products derived from this software without specific prior
|
|
Packit |
eace71 |
* written permission.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
Packit |
eace71 |
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
Packit |
eace71 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
eace71 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
Packit |
eace71 |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
eace71 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
Packit |
eace71 |
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
eace71 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
Packit |
eace71 |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
eace71 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
eace71 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* ping.c - Ping implementation for iscsiuio using ICMP/ICMPv6
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <pthread.h>
|
|
Packit |
eace71 |
#include <signal.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <time.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <sys/time.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/stat.h>
|
|
Packit |
eace71 |
#include <netinet/in.h>
|
|
Packit |
eace71 |
#include <arpa/inet.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "iscsi_if.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "uip.h"
|
|
Packit |
eace71 |
#include "uip_arp.h"
|
|
Packit |
eace71 |
#include "uip_eth.h"
|
|
Packit |
eace71 |
#include "dhcpc.h"
|
|
Packit |
eace71 |
#include "ipv6_ndpc.h"
|
|
Packit |
eace71 |
#include "ipv6.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "logger.h"
|
|
Packit |
eace71 |
#include "nic.h"
|
|
Packit |
eace71 |
#include "nic_utils.h"
|
|
Packit |
eace71 |
#include "options.h"
|
|
Packit |
eace71 |
#include "packet.h"
|
|
Packit |
eace71 |
#include "bnx2.h"
|
|
Packit |
eace71 |
#include "bnx2x.h"
|
|
Packit |
eace71 |
#include "cnic.h"
|
|
Packit |
eace71 |
#include "ping.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define PFX "ping "
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void fill_payload_data(struct uip_stack *ustack)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (ustack->uip_slen)
|
|
Packit |
eace71 |
memset(ustack->uip_appdata, 'A', ustack->uip_slen);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int prepare_icmpv4_req_pkt(struct ping_conf *png_c, struct packet *pkt,
|
|
Packit |
eace71 |
uip_ip4addr_t *dst_addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
nic_interface_t *nic_iface = png_c->nic_iface;
|
|
Packit |
eace71 |
struct uip_stack *ustack = &nic_iface->ustack;
|
|
Packit |
eace71 |
struct uip_ipv4_hdr *ipv4_hdr = NULL;
|
|
Packit |
eace71 |
struct uip_icmpv4_hdr *icmpv4_hdr = NULL;
|
|
Packit |
eace71 |
u16_t uip_iph_len = 0;
|
|
Packit |
eace71 |
u16_t icmpv4_hdr_len = 0;
|
|
Packit |
eace71 |
u16_t uip_ip_icmph_len = 0;
|
|
Packit |
eace71 |
int mtu = 1500;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
uip_iph_len = UIP_IPv4_H_LEN;
|
|
Packit |
eace71 |
icmpv4_hdr_len = sizeof(*icmpv4_hdr);
|
|
Packit |
eace71 |
uip_ip_icmph_len = uip_iph_len + icmpv4_hdr_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ipv4_hdr = (struct uip_ipv4_hdr *)ustack->network_layer;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
icmpv4_hdr = (struct uip_icmpv4_hdr *) (ustack->network_layer +
|
|
Packit |
eace71 |
sizeof(struct uip_ipv4_hdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* fill IP header */
|
|
Packit |
eace71 |
ipv4_hdr->vhl = 0x45;
|
|
Packit |
eace71 |
ipv4_hdr->tos = 0;
|
|
Packit |
eace71 |
++ustack->ipid;
|
|
Packit |
eace71 |
ipv4_hdr->ipid[0] = ustack->ipid >> 8;
|
|
Packit |
eace71 |
ipv4_hdr->ipid[1] = ustack->ipid & 0xff;
|
|
Packit |
eace71 |
ipv4_hdr->ipoffset[0] = 0;
|
|
Packit |
eace71 |
ipv4_hdr->ipoffset[1] = 0;
|
|
Packit |
eace71 |
ipv4_hdr->ttl = UIP_TTL;
|
|
Packit |
eace71 |
ipv4_hdr->proto = UIP_PROTO_ICMP;
|
|
Packit |
eace71 |
uip_ip4addr_copy(ipv4_hdr->srcipaddr, ustack->hostaddr);
|
|
Packit |
eace71 |
uip_ip4addr_copy(ipv4_hdr->destipaddr, dst_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "src ipaddr: %d.%d.%d.%d",
|
|
Packit |
eace71 |
uip_ipaddr1(ipv4_hdr->srcipaddr),
|
|
Packit |
eace71 |
uip_ipaddr2(ipv4_hdr->srcipaddr),
|
|
Packit |
eace71 |
uip_ipaddr3(ipv4_hdr->srcipaddr),
|
|
Packit |
eace71 |
uip_ipaddr4(ipv4_hdr->srcipaddr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "dest ipaddr: %d.%d.%d.%d",
|
|
Packit |
eace71 |
uip_ipaddr1(ipv4_hdr->destipaddr),
|
|
Packit |
eace71 |
uip_ipaddr2(ipv4_hdr->destipaddr),
|
|
Packit |
eace71 |
uip_ipaddr3(ipv4_hdr->destipaddr),
|
|
Packit |
eace71 |
uip_ipaddr4(ipv4_hdr->destipaddr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* fill ICMP header */
|
|
Packit |
eace71 |
icmpv4_hdr->type = ICMP_ECHO;
|
|
Packit |
eace71 |
icmpv4_hdr->icode = 0;
|
|
Packit |
eace71 |
icmpv4_hdr->id = getpid() & 0xffff;
|
|
Packit |
eace71 |
png_c->id = icmpv4_hdr->id;
|
|
Packit |
eace71 |
icmpv4_hdr->seqno = ustack->ipid;
|
|
Packit |
eace71 |
png_c->seqno =icmpv4_hdr->seqno;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* appdata and sappdata point to the icmp payload */
|
|
Packit |
eace71 |
ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len;
|
|
Packit |
eace71 |
ustack->uip_sappdata = ustack->uip_appdata;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->mtu)
|
|
Packit |
eace71 |
mtu = nic_iface->mtu;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((mtu - uip_ip_icmph_len) > png_c->datalen) {
|
|
Packit |
eace71 |
ustack->uip_slen = png_c->datalen;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
png_c->state = ISCSI_PING_OVERSIZE_PACKET;
|
|
Packit |
eace71 |
LOG_ERR(PFX "MTU=%d, payload=%d\n",
|
|
Packit |
eace71 |
mtu, png_c->datalen);
|
|
Packit |
eace71 |
rc = -EINVAL;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fill_payload_data(ustack);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Calculate ICMP checksum. */
|
|
Packit |
eace71 |
icmpv4_hdr->icmpchksum = 0;
|
|
Packit |
eace71 |
icmpv4_hdr->icmpchksum = ~(uip_chksum((u16_t *)icmpv4_hdr,
|
|
Packit |
eace71 |
icmpv4_hdr_len +
|
|
Packit |
eace71 |
ustack->uip_slen));
|
|
Packit |
eace71 |
if (icmpv4_hdr->icmpchksum == 0)
|
|
Packit |
eace71 |
icmpv4_hdr->icmpchksum = 0xffff;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* IPv4 total length = IPv4 HLEN + ICMP HLEN + Payload len */
|
|
Packit |
eace71 |
ustack->uip_len = uip_ip_icmph_len + ustack->uip_slen;
|
|
Packit |
eace71 |
ipv4_hdr->len[0] = (ustack->uip_len >> 8);
|
|
Packit |
eace71 |
ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Calculate IP checksum. */
|
|
Packit |
eace71 |
ipv4_hdr->ipchksum = 0;
|
|
Packit |
eace71 |
ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack));
|
|
Packit |
eace71 |
if (ipv4_hdr->ipchksum == 0)
|
|
Packit |
eace71 |
ipv4_hdr->ipchksum = 0xffff;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
++ustack->stats.ip.sent;
|
|
Packit |
eace71 |
/* Return and let the caller do the actual transmission. */
|
|
Packit |
eace71 |
ustack->uip_flags = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void prepare_icmpv6_req_pkt(struct ping_conf *png_c, struct packet *pkt,
|
|
Packit |
eace71 |
uip_ip6addr_t *dst_addr,
|
|
Packit |
eace71 |
uip_ip6addr_t *src_addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
nic_interface_t *nic_iface = png_c->nic_iface;
|
|
Packit |
eace71 |
struct uip_stack *ustack = &nic_iface->ustack;
|
|
Packit |
eace71 |
struct uip_ipv6_hdr *ipv6_hdr = NULL;
|
|
Packit |
eace71 |
uip_icmp_echo_hdr_t *icmp_echo_hdr = NULL;
|
|
Packit |
eace71 |
u16_t uip_iph_len = 0;
|
|
Packit |
eace71 |
u16_t icmp_echo_hdr_len = 0;
|
|
Packit |
eace71 |
u16_t uip_ip_icmph_len = 0;
|
|
Packit |
eace71 |
char ipbuf[INET6_ADDRSTRLEN] = {0};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
uip_iph_len = UIP_IPv6_H_LEN;
|
|
Packit |
eace71 |
icmp_echo_hdr_len = sizeof(*icmp_echo_hdr);
|
|
Packit |
eace71 |
uip_ip_icmph_len = uip_iph_len + icmp_echo_hdr_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ipv6_hdr = (struct uip_ipv6_hdr *)ustack->network_layer;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
icmp_echo_hdr = (uip_icmp_echo_hdr_t *) (ustack->network_layer +
|
|
Packit |
eace71 |
sizeof(struct uip_ipv6_hdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* fill IPv6 header */
|
|
Packit |
eace71 |
ipv6_hdr->vtc = 0x60;
|
|
Packit |
eace71 |
ipv6_hdr->tcflow = 0;
|
|
Packit |
eace71 |
ipv6_hdr->flow = 0;
|
|
Packit |
eace71 |
ipv6_hdr->proto = UIP_PROTO_ICMP6;
|
|
Packit |
eace71 |
ipv6_hdr->ttl = UIP_TTL;
|
|
Packit |
eace71 |
uip_ip6addr_copy(ipv6_hdr->srcipaddr, src_addr);
|
|
Packit |
eace71 |
uip_ip6addr_copy(ipv6_hdr->destipaddr, dst_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(ipbuf, 0, sizeof(ipbuf));
|
|
Packit |
eace71 |
if (inet_ntop(AF_INET6, &ipv6_hdr->srcipaddr, ipbuf, INET6_ADDRSTRLEN))
|
|
Packit |
eace71 |
LOG_INFO(PFX "src ipaddr=%s", ipbuf);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(ipbuf, 0, sizeof(ipbuf));
|
|
Packit |
eace71 |
if (inet_ntop(AF_INET6, &ipv6_hdr->destipaddr, ipbuf, INET6_ADDRSTRLEN))
|
|
Packit |
eace71 |
LOG_INFO(PFX "dest ipaddr=%s", ipbuf);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* fill ICMP header */
|
|
Packit |
eace71 |
icmp_echo_hdr->type = ICMPV6_ECHO_REQ;
|
|
Packit |
eace71 |
icmp_echo_hdr->icode = 0;
|
|
Packit |
eace71 |
icmp_echo_hdr->id = HOST_TO_NET16(getpid() & 0xffff);
|
|
Packit |
eace71 |
png_c->id = icmp_echo_hdr->id;
|
|
Packit |
eace71 |
++ustack->ipid;
|
|
Packit |
eace71 |
icmp_echo_hdr->seqno = HOST_TO_NET16(ustack->ipid);
|
|
Packit |
eace71 |
png_c->seqno = icmp_echo_hdr->seqno;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* appdata and sappdata point to the icmp payload */
|
|
Packit |
eace71 |
ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len;
|
|
Packit |
eace71 |
ustack->uip_sappdata = ustack->uip_appdata;
|
|
Packit |
eace71 |
ustack->uip_slen = png_c->datalen;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fill_payload_data(ustack);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Total length = ETH HLEN + IPv6 HLEN + ICMP HLEN + Data len */
|
|
Packit |
eace71 |
ustack->uip_len = UIP_LLH_LEN + uip_ip_icmph_len + ustack->uip_slen;
|
|
Packit |
eace71 |
/* IPv6 payload len */
|
|
Packit |
eace71 |
ipv6_hdr->len = HOST_TO_NET16(icmp_echo_hdr_len + ustack->uip_slen);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Calculate ICMP checksum. */
|
|
Packit |
eace71 |
icmp_echo_hdr->icmpchksum = 0;
|
|
Packit |
eace71 |
icmp_echo_hdr->icmpchksum = ~(uip_icmp6chksum(ustack));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
++ustack->stats.ip.sent;
|
|
Packit |
eace71 |
/* Return and let the caller do the actual transmission. */
|
|
Packit |
eace71 |
ustack->uip_flags = 0;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int chk_arp_entry_for_dst_addr(nic_t *nic, nic_interface_t *nic_iface,
|
|
Packit |
eace71 |
void *addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_path path;
|
|
Packit |
eace71 |
uip_ip4addr_t dst_addr4;
|
|
Packit |
eace71 |
uip_ip6addr_t dst_addr6;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->protocol == AF_INET) {
|
|
Packit |
eace71 |
memcpy(dst_addr4, addr, sizeof(uip_ip4addr_t));
|
|
Packit |
eace71 |
memcpy(&path.dst.v4_addr, dst_addr4, sizeof(struct in_addr));
|
|
Packit |
eace71 |
path.ip_addr_len = 4;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
memcpy(dst_addr6, addr, sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
memcpy(&path.dst.v6_addr, dst_addr6, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
path.ip_addr_len = 16;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return cnic_handle_iscsi_path_req(nic, 0, NULL, &path, nic_iface);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int fill_icmpv6_eth_hdr(struct uip_stack *ustack,
|
|
Packit |
eace71 |
uip_ip6addr_t *dst_addr6)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct uip_eth_hdr *eth;
|
|
Packit |
eace71 |
__u8 mac_addr[6];
|
|
Packit |
eace71 |
struct ndpc_reqptr req_ptr;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
int ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
eth = (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
Packit |
eace71 |
memcpy(eth->src.addr, ustack->uip_ethaddr.addr, sizeof(eth->src.addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(mac_addr, 0, sizeof(mac_addr));
|
|
Packit |
eace71 |
req_ptr.eth = (void *)mac_addr;
|
|
Packit |
eace71 |
req_ptr.ipv6 = (void *)dst_addr6;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ret = ndpc_request(ustack, &req_ptr, &rc, CHECK_ARP_TABLE);
|
|
Packit |
eace71 |
if (ret) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "ndpc request failed");
|
|
Packit |
eace71 |
rc = ret;
|
|
Packit |
eace71 |
} else if (rc) {
|
|
Packit |
eace71 |
memcpy(eth->dest.addr, mac_addr, sizeof(eth->dest.addr));
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "ipv6 arp entry present");
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "ipv6 arp entry not present");
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int determine_src_ipv6_addr(nic_interface_t *nic_iface,
|
|
Packit |
eace71 |
uip_ip6addr_t *dst_addr6,
|
|
Packit |
eace71 |
uip_ip6addr_t *src_addr6)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct in6_addr *addr;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
int ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
|
|
Packit |
eace71 |
memcpy(src_addr6, &nic_iface->ustack.hostaddr6,
|
|
Packit |
eace71 |
sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ret = ndpc_request(&nic_iface->ustack, dst_addr6,
|
|
Packit |
eace71 |
&rc, CHECK_LINK_LOCAL_ADDR);
|
|
Packit |
eace71 |
if (ret) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Check LL failed");
|
|
Packit |
eace71 |
rc = ret;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Use LL");
|
|
Packit |
eace71 |
/* Get link local IPv6 address */
|
|
Packit |
eace71 |
addr = (struct in6_addr *)&nic_iface->ustack.linklocal6;
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Use Best matched");
|
|
Packit |
eace71 |
ret = ndpc_request(&nic_iface->ustack,
|
|
Packit |
eace71 |
dst_addr6,
|
|
Packit |
eace71 |
&addr, GET_HOST_ADDR);
|
|
Packit |
eace71 |
if (ret) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Use Best matched failed");
|
|
Packit |
eace71 |
rc = ret;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (addr == NULL) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "No Best matched found");
|
|
Packit |
eace71 |
rc = -EINVAL;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Got the best matched src IP address */
|
|
Packit |
eace71 |
memcpy(src_addr6, addr, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void ping_init(struct ping_conf *png_c, void *addr, u16_t type, int datalen)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
png_c->dst_addr = addr;
|
|
Packit |
eace71 |
png_c->proto = type;
|
|
Packit |
eace71 |
png_c->state = PING_INIT_STATE;
|
|
Packit |
eace71 |
png_c->datalen = datalen;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int do_ping_from_nic_iface(struct ping_conf *png_c)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
packet_t *pkt;
|
|
Packit |
eace71 |
nic_interface_t *nic_iface = png_c->nic_iface;
|
|
Packit |
eace71 |
nic_t *nic = nic_iface->parent;
|
|
Packit |
eace71 |
struct uip_stack *ustack = &nic_iface->ustack;
|
|
Packit |
eace71 |
uip_ip4addr_t dst_addr4;
|
|
Packit |
eace71 |
uip_ip6addr_t dst_addr6;
|
|
Packit |
eace71 |
uip_ip6addr_t src_addr6;
|
|
Packit |
eace71 |
struct timer ping_timer;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(dst_addr4, 0, sizeof(uip_ip4addr_t));
|
|
Packit |
eace71 |
memset(dst_addr6, 0, sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
memset(src_addr6, 0, sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->protocol == AF_INET)
|
|
Packit |
eace71 |
memcpy(dst_addr4, png_c->dst_addr, sizeof(uip_ip4addr_t));
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
memcpy(dst_addr6, png_c->dst_addr, sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = chk_arp_entry_for_dst_addr(nic, nic_iface, png_c->dst_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc && (nic_iface->protocol == AF_INET)) {
|
|
Packit |
eace71 |
png_c->state = ISCSI_PING_NO_ARP_RECEIVED;
|
|
Packit |
eace71 |
LOG_ERR(PFX "ARP failure for IPv4 dest addr");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
} else if ((rc < 1) && (nic_iface->protocol == AF_INET6)) {
|
|
Packit |
eace71 |
png_c->state = ISCSI_PING_NO_ARP_RECEIVED;
|
|
Packit |
eace71 |
LOG_ERR(PFX "ARP failure for IPv6 dest addr");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
} else if (rc < 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "ARP failure");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
pkt = get_next_free_packet(nic);
|
|
Packit |
eace71 |
if (pkt == NULL) {
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
LOG_ERR(PFX "Unable to get a free packet buffer");
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_ustack(nic, nic_iface, ustack, pkt);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->protocol == AF_INET) {
|
|
Packit |
eace71 |
rc = prepare_icmpv4_req_pkt(png_c, pkt, &dst_addr4);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto put_pkt;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* If the above function invocation resulted
|
|
Packit |
eace71 |
* in data that should be sent out on the
|
|
Packit |
eace71 |
* network, the global variable uip_len is
|
|
Packit |
eace71 |
* set to a value > 0. */
|
|
Packit |
eace71 |
if (ustack->uip_len > 0) {
|
|
Packit |
eace71 |
pkt->buf_size = ustack->uip_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_ipv4_packet(nic, nic_iface, ustack, pkt);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Send ICMP echo request");
|
|
Packit |
eace71 |
(*nic->ops->write) (nic, nic_iface, pkt);
|
|
Packit |
eace71 |
ustack->uip_len = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
rc = determine_src_ipv6_addr(nic_iface, &dst_addr6, &src_addr6);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto put_pkt;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_icmpv6_req_pkt(png_c, pkt, &dst_addr6, &src_addr6);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* If the above function invocation resulted
|
|
Packit |
eace71 |
* in data that should be sent out on the
|
|
Packit |
eace71 |
* network, the global variable uip_len is
|
|
Packit |
eace71 |
* set to a value > 0. */
|
|
Packit |
eace71 |
if (ustack->uip_len > 0) {
|
|
Packit |
eace71 |
pkt->buf_size = ustack->uip_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_ipv6_packet(nic, nic_iface, ustack, pkt);
|
|
Packit |
eace71 |
rc = fill_icmpv6_eth_hdr(ustack, &dst_addr6);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
ustack->uip_len = 0;
|
|
Packit |
eace71 |
goto put_pkt;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Send ICMPv6 echo request");
|
|
Packit |
eace71 |
(*nic->ops->write) (nic, nic_iface, pkt);
|
|
Packit |
eace71 |
ustack->uip_len = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
put_pkt:
|
|
Packit |
eace71 |
put_packet_in_free_queue(pkt, nic);
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Ping request not transmitted");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
timer_set(&ping_timer, CLOCK_SECOND * 10);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while ((event_loop_stop == 0) &&
|
|
Packit |
eace71 |
(nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = nic_process_intr(nic, 1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) {
|
|
Packit |
eace71 |
rc = process_packets(nic, NULL, NULL, nic_iface);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!rc && (png_c->state == ISCSI_PING_SUCCESS)) {
|
|
Packit |
eace71 |
LOG_INFO(PFX "PING successful!");
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (timer_expired(&ping_timer)) {
|
|
Packit |
eace71 |
png_c->state = ISCSI_PING_TIMEOUT;
|
|
Packit |
eace71 |
LOG_ERR(PFX "PING timeout");
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int process_icmp_packet(uip_icmp_echo_hdr_t *icmp_hdr,
|
|
Packit |
eace71 |
struct uip_stack *ustack)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct ping_conf *png_c = (struct ping_conf *)ustack->ping_conf;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "Verify ICMP echo reply");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((icmp_hdr->type == ICMPV6_ECHO_REPLY &&
|
|
Packit |
eace71 |
png_c->proto == AF_INET6) ||
|
|
Packit |
eace71 |
(icmp_hdr->type == ICMP_ECHO_REPLY &&
|
|
Packit |
eace71 |
png_c->proto == AF_INET)) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((icmp_hdr->icode == 0) &&
|
|
Packit |
eace71 |
(icmp_hdr->id == png_c->id) &&
|
|
Packit |
eace71 |
(icmp_hdr->seqno == png_c->seqno)) {
|
|
Packit |
eace71 |
png_c->state = ISCSI_PING_SUCCESS;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
rc = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
rc = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
LOG_INFO(PFX "ICMP echo reply verification failed!");
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_INFO(PFX "ICMP echo reply OK");
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|