|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (c) 2009-2011, Broadcom Corporation
|
|
Packit |
eace71 |
* Copyright (c) 2014, QLogic Corporation
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Written by: Benjamin Li (benli@broadcom.com)
|
|
Packit |
eace71 |
*
|
|
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 |
* iscsi_ipc.c - Generic NIC management/utility functions
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define _GNU_SOURCE
|
|
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 <stdio.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <arpa/inet.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <sys/time.h>
|
|
Packit |
eace71 |
#include <sys/un.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <pwd.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define PFX "iscsi_ipc "
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* TODO fix me */
|
|
Packit |
eace71 |
#define IFNAMSIZ 15
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "nic.h"
|
|
Packit |
eace71 |
#include "nic_utils.h"
|
|
Packit |
eace71 |
#include "nic_vlan.h"
|
|
Packit |
eace71 |
#include "options.h"
|
|
Packit |
eace71 |
#include "mgmt_ipc.h"
|
|
Packit |
eace71 |
#include "iscsid_ipc.h"
|
|
Packit |
eace71 |
#include "uip.h"
|
|
Packit |
eace71 |
#include "uip_mgmt_ipc.h"
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "logger.h"
|
|
Packit |
eace71 |
#include "uip.h"
|
|
Packit |
eace71 |
#include "ping.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* private iscsid options stucture */
|
|
Packit |
eace71 |
struct iscsid_options {
|
|
Packit |
eace71 |
int fd;
|
|
Packit |
eace71 |
pthread_t thread;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iface_rec_decode {
|
|
Packit |
eace71 |
/* General */
|
|
Packit |
eace71 |
int32_t iface_num;
|
|
Packit |
eace71 |
uint32_t ip_type;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* IPv4 */
|
|
Packit |
eace71 |
struct in_addr ipv4_addr;
|
|
Packit |
eace71 |
struct in_addr ipv4_subnet_mask;
|
|
Packit |
eace71 |
struct in_addr ipv4_gateway;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* IPv6 */
|
|
Packit |
eace71 |
struct in6_addr ipv6_addr;
|
|
Packit |
eace71 |
struct in6_addr ipv6_subnet_mask;
|
|
Packit |
eace71 |
uint32_t prefix_len;
|
|
Packit |
eace71 |
struct in6_addr ipv6_linklocal;
|
|
Packit |
eace71 |
struct in6_addr ipv6_router;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
uint8_t ipv6_autocfg;
|
|
Packit |
eace71 |
uint8_t linklocal_autocfg;
|
|
Packit |
eace71 |
uint8_t router_autocfg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
uint8_t vlan_state;
|
|
Packit |
eace71 |
uint8_t vlan_priority;
|
|
Packit |
eace71 |
uint16_t vlan_id;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define MIN_MTU_SUPPORT 46
|
|
Packit |
eace71 |
#define MAX_MTU_SUPPORT 9000
|
|
Packit |
eace71 |
uint16_t mtu;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define PEERUSER_MAX 64
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/******************************************************************************
|
|
Packit |
eace71 |
* Globals
|
|
Packit |
eace71 |
*****************************************************************************/
|
|
Packit |
eace71 |
static struct iscsid_options iscsid_opts = {
|
|
Packit |
eace71 |
.fd = INVALID_FD,
|
|
Packit |
eace71 |
.thread = INVALID_THREAD,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/******************************************************************************
|
|
Packit |
eace71 |
* iscsid Functions
|
|
Packit |
eace71 |
*****************************************************************************/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void *enable_nic_thread(void *data)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
nic_t *nic = (nic_t *) data;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_nic_thread(nic);
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: started NIC enable thread state: 0x%x",
|
|
Packit |
eace71 |
nic->log_name, nic->state)
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Enable the NIC */
|
|
Packit |
eace71 |
nic_enable(nic);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic->enable_thread = INVALID_THREAD;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_exit(NULL);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int decode_cidr(char *in_ipaddr_str, struct iface_rec_decode *ird)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0, i;
|
|
Packit |
eace71 |
char *tmp, *tok;
|
|
Packit |
eace71 |
char ipaddr_str[NI_MAXHOST];
|
|
Packit |
eace71 |
char str[INET6_ADDRSTRLEN];
|
|
Packit |
eace71 |
unsigned long keepbits = 0;
|
|
Packit |
eace71 |
struct in_addr ia;
|
|
Packit |
eace71 |
struct in6_addr ia6;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(ipaddr_str, in_ipaddr_str, NI_MAXHOST);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Find the CIDR if any */
|
|
Packit |
eace71 |
tmp = strchr(ipaddr_str, '/');
|
|
Packit |
eace71 |
if (tmp) {
|
|
Packit |
eace71 |
/* CIDR found, now decode, tmpbuf = ip, tmp = netmask */
|
|
Packit |
eace71 |
tmp = ipaddr_str;
|
|
Packit |
eace71 |
tok = strsep(&tmp, "/");
|
|
Packit |
eace71 |
LOG_INFO(PFX "in cidr: bitmask '%s' ip '%s'", tmp, tok);
|
|
Packit |
eace71 |
keepbits = strtoull(tmp, NULL, 10);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Determine if the IP address passed from the iface file is
|
|
Packit |
eace71 |
* an IPv4 or IPv6 address */
|
|
Packit |
eace71 |
rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv6_addr);
|
|
Packit |
eace71 |
if (rc == 0) {
|
|
Packit |
eace71 |
/* Test to determine if the addres is an IPv6 address */
|
|
Packit |
eace71 |
rc = inet_pton(AF_INET6, ipaddr_str, &ird->ipv6_addr);
|
|
Packit |
eace71 |
if (rc == 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not parse IP address: '%s'",
|
|
Packit |
eace71 |
ipaddr_str);
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ird->ip_type = AF_INET6;
|
|
Packit |
eace71 |
if (keepbits > 128) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "CIDR netmask > 128 for IPv6: %d(%s)",
|
|
Packit |
eace71 |
keepbits, tmp);
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (!keepbits) {
|
|
Packit |
eace71 |
/* Default prefix mask to 64 */
|
|
Packit |
eace71 |
memcpy(&ird->ipv6_subnet_mask.s6_addr, all_zeroes_addr6,
|
|
Packit |
eace71 |
sizeof(struct in6_addr));
|
|
Packit |
eace71 |
ird->prefix_len = 64;
|
|
Packit |
eace71 |
for (i = 0; i < 2; i++)
|
|
Packit |
eace71 |
ird->ipv6_subnet_mask.s6_addr32[i] = 0xffffffff;
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ird->prefix_len = keepbits;
|
|
Packit |
eace71 |
memcpy(&ia6.s6_addr, all_zeroes_addr6, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
for (i = 0; i < 4; i++) {
|
|
Packit |
eace71 |
if (keepbits < 32) {
|
|
Packit |
eace71 |
ia6.s6_addr32[i] = keepbits > 0 ?
|
|
Packit |
eace71 |
0x00 - (1 << (32 - keepbits)) : 0;
|
|
Packit |
eace71 |
ia6.s6_addr32[i] = htonl(ia6.s6_addr32[i]);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
ia6.s6_addr32[i] = 0xFFFFFFFF;
|
|
Packit |
eace71 |
keepbits -= 32;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ird->ipv6_subnet_mask = ia6;
|
|
Packit |
eace71 |
if (inet_ntop(AF_INET6, &ia6, str, sizeof(str)))
|
|
Packit |
eace71 |
LOG_INFO(PFX "Using netmask: %s", str);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
ird->ip_type = AF_INET;
|
|
Packit |
eace71 |
rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv4_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (keepbits > 32) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "CIDR netmask > 32 for IPv4: %d(%s)",
|
|
Packit |
eace71 |
keepbits, tmp);
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ia.s_addr = keepbits > 0 ? 0x00 - (1 << (32 - keepbits)) : 0;
|
|
Packit |
eace71 |
ird->ipv4_subnet_mask.s_addr = htonl(ia.s_addr);
|
|
Packit |
eace71 |
LOG_INFO(PFX "Using netmask: %s",
|
|
Packit |
eace71 |
inet_ntoa(ird->ipv4_subnet_mask));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int decode_iface(struct iface_rec_decode *ird, struct iface_rec *rec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
char ipaddr_str[NI_MAXHOST];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Decodes the rec contents */
|
|
Packit |
eace71 |
memset(ird, 0, sizeof(struct iface_rec_decode));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Detect for CIDR notation and strip off the netmask if present */
|
|
Packit |
eace71 |
rc = decode_cidr(rec->ipaddress, ird);
|
|
Packit |
eace71 |
if (rc && !ird->ip_type) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "cidr decode err: rc=%d, ip_type=%d",
|
|
Packit |
eace71 |
rc, ird->ip_type);
|
|
Packit |
eace71 |
/* Can't decode address, just exit */
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
ird->iface_num = rec->iface_num;
|
|
Packit |
eace71 |
ird->vlan_id = rec->vlan_id;
|
|
Packit |
eace71 |
if (rec->iface_num != IFACE_NUM_INVALID) {
|
|
Packit |
eace71 |
ird->mtu = rec->mtu;
|
|
Packit |
eace71 |
if (rec->vlan_id && strcmp(rec->vlan_state, "disable")) {
|
|
Packit |
eace71 |
ird->vlan_state = 1;
|
|
Packit |
eace71 |
ird->vlan_priority = rec->vlan_priority;
|
|
Packit |
eace71 |
ird->vlan_id = rec->vlan_id;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (ird->ip_type == AF_INET6) {
|
|
Packit |
eace71 |
if (!strcmp(rec->ipv6_autocfg, "dhcpv6"))
|
|
Packit |
eace71 |
ird->ipv6_autocfg = IPV6_AUTOCFG_DHCPV6;
|
|
Packit |
eace71 |
else if (!strcmp(rec->ipv6_autocfg, "nd"))
|
|
Packit |
eace71 |
ird->ipv6_autocfg = IPV6_AUTOCFG_ND;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
ird->ipv6_autocfg = IPV6_AUTOCFG_NOTSPEC;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strcmp(rec->linklocal_autocfg, "auto"))
|
|
Packit |
eace71 |
ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON;
|
|
Packit |
eace71 |
else if (!strcmp(rec->linklocal_autocfg, "off"))
|
|
Packit |
eace71 |
ird->linklocal_autocfg = IPV6_LL_AUTOCFG_OFF;
|
|
Packit |
eace71 |
else /* default */
|
|
Packit |
eace71 |
ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strcmp(rec->router_autocfg, "auto"))
|
|
Packit |
eace71 |
ird->router_autocfg = IPV6_RTR_AUTOCFG_ON;
|
|
Packit |
eace71 |
else if (!strcmp(rec->router_autocfg, "off"))
|
|
Packit |
eace71 |
ird->router_autocfg = IPV6_RTR_AUTOCFG_OFF;
|
|
Packit |
eace71 |
else /* default */
|
|
Packit |
eace71 |
ird->router_autocfg = IPV6_RTR_AUTOCFG_ON;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Decode the addresses based on the control flags */
|
|
Packit |
eace71 |
/* For DHCP, ignore the IPv6 addr in the iface */
|
|
Packit |
eace71 |
if (ird->ipv6_autocfg == IPV6_AUTOCFG_DHCPV6)
|
|
Packit |
eace71 |
memcpy(&ird->ipv6_addr, all_zeroes_addr6,
|
|
Packit |
eace71 |
sizeof(struct in6_addr));
|
|
Packit |
eace71 |
/* Subnet mask priority: CIDR, then rec */
|
|
Packit |
eace71 |
if (!ird->ipv6_subnet_mask.s6_addr)
|
|
Packit |
eace71 |
inet_pton(AF_INET6, rec->subnet_mask,
|
|
Packit |
eace71 |
&ird->ipv6_subnet_mask);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* For LL on, ignore the IPv6 addr in the iface */
|
|
Packit |
eace71 |
if (ird->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) {
|
|
Packit |
eace71 |
strlcpy(ipaddr_str, rec->ipv6_linklocal,
|
|
Packit |
eace71 |
NI_MAXHOST);
|
|
Packit |
eace71 |
inet_pton(AF_INET6, ipaddr_str,
|
|
Packit |
eace71 |
&ird->ipv6_linklocal);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* For RTR on, ignore the IPv6 addr in the iface */
|
|
Packit |
eace71 |
if (ird->router_autocfg == IPV6_RTR_AUTOCFG_OFF) {
|
|
Packit |
eace71 |
strlcpy(ipaddr_str, rec->ipv6_router,
|
|
Packit |
eace71 |
NI_MAXHOST);
|
|
Packit |
eace71 |
inet_pton(AF_INET6, ipaddr_str,
|
|
Packit |
eace71 |
&ird->ipv6_router);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* Subnet mask priority: CIDR, rec, default */
|
|
Packit |
eace71 |
if (!ird->ipv4_subnet_mask.s_addr)
|
|
Packit |
eace71 |
inet_pton(AF_INET, rec->subnet_mask,
|
|
Packit |
eace71 |
&ird->ipv4_subnet_mask);
|
|
Packit |
eace71 |
if (!ird->ipv4_subnet_mask.s_addr)
|
|
Packit |
eace71 |
ird->ipv4_subnet_mask.s_addr =
|
|
Packit |
eace71 |
calculate_default_netmask(
|
|
Packit |
eace71 |
ird->ipv4_addr.s_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(ipaddr_str, rec->gateway, NI_MAXHOST);
|
|
Packit |
eace71 |
inet_pton(AF_INET, ipaddr_str, &ird->ipv4_gateway);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
ird->ipv6_autocfg = IPV6_AUTOCFG_NOTUSED;
|
|
Packit |
eace71 |
ird->linklocal_autocfg = IPV6_LL_AUTOCFG_NOTUSED;
|
|
Packit |
eace71 |
ird->router_autocfg = IPV6_RTR_AUTOCFG_NOTUSED;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void *perform_ping(void *arg)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct ping_conf *png_c = (struct ping_conf *)arg;
|
|
Packit |
eace71 |
nic_interface_t *nic_iface = png_c->nic_iface;
|
|
Packit |
eace71 |
nic_t *nic = nic_iface->parent;
|
|
Packit |
eace71 |
iscsid_uip_broadcast_t *data;
|
|
Packit |
eace71 |
struct sockaddr_in *addr;
|
|
Packit |
eace71 |
struct sockaddr_in6 *addr6;
|
|
Packit |
eace71 |
uip_ip6addr_t dst_addr;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
int datalen;
|
|
Packit |
eace71 |
struct timespec ts = {.tv_sec = 5,
|
|
Packit |
eace71 |
.tv_nsec = 0};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
data = (iscsid_uip_broadcast_t *)png_c->data;
|
|
Packit |
eace71 |
datalen = data->u.ping_rec.datalen;
|
|
Packit |
eace71 |
if ((datalen > STD_MTU_SIZE) || (datalen < 0)) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Ping datalen invalid: %d", datalen);
|
|
Packit |
eace71 |
rc = -EINVAL;
|
|
Packit |
eace71 |
goto ping_done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(dst_addr, 0, sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
if (nic_iface->protocol == AF_INET) {
|
|
Packit |
eace71 |
/* IPv4 */
|
|
Packit |
eace71 |
addr = (struct sockaddr_in *)&data->u.ping_rec.ipaddr;
|
|
Packit |
eace71 |
memcpy(dst_addr, &addr->sin_addr.s_addr, sizeof(uip_ip4addr_t));
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* IPv6 */
|
|
Packit |
eace71 |
addr6 = (struct sockaddr_in6 *)&data->u.ping_rec.ipaddr;
|
|
Packit |
eace71 |
memcpy(dst_addr, &addr6->sin6_addr.s6_addr,
|
|
Packit |
eace71 |
sizeof(uip_ip6addr_t));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Ensure that the NIC is RUNNING */
|
|
Packit |
eace71 |
if ((nic->state != NIC_RUNNING) || !(nic->flags & NIC_ENABLED)) {
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
rc = pthread_cond_timedwait(&nic->enable_done_cond,
|
|
Packit |
eace71 |
&nic->nic_mutex, &ts);
|
|
Packit |
eace71 |
if ((rc == 0) && (nic->state == NIC_RUNNING)) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "%s: nic running", nic->log_name);
|
|
Packit |
eace71 |
} else if (rc) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "%s: err %d", nic->log_name, rc);
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc || nic->state != NIC_RUNNING) {
|
|
Packit |
eace71 |
png_c->state = rc;
|
|
Packit |
eace71 |
goto ping_done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ping_init(png_c, dst_addr, nic_iface->protocol, datalen);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = do_ping_from_nic_iface(png_c);
|
|
Packit |
eace71 |
if (png_c->state == -1)
|
|
Packit |
eace71 |
png_c->state = rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ping_done:
|
|
Packit |
eace71 |
LOG_INFO(PFX "ping thread end");
|
|
Packit |
eace71 |
nic->ping_thread = INVALID_THREAD;
|
|
Packit |
eace71 |
pthread_exit(NULL);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int parse_iface(void *arg, int do_ping)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, i;
|
|
Packit |
eace71 |
nic_t *nic = NULL;
|
|
Packit |
eace71 |
nic_interface_t *nic_iface;
|
|
Packit |
eace71 |
char *transport_name;
|
|
Packit |
eace71 |
size_t transport_name_size;
|
|
Packit |
eace71 |
nic_lib_handle_t *handle;
|
|
Packit |
eace71 |
iscsid_uip_broadcast_t *data;
|
|
Packit |
eace71 |
char ipv6_buf_str[INET6_ADDRSTRLEN];
|
|
Packit |
eace71 |
int request_type = 0;
|
|
Packit |
eace71 |
struct iface_rec *rec;
|
|
Packit |
eace71 |
struct iface_rec_decode ird;
|
|
Packit |
eace71 |
struct in_addr src_match, dst_match;
|
|
Packit |
eace71 |
pthread_attr_t attr;
|
|
Packit |
eace71 |
struct ping_conf *png_c;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
data = (iscsid_uip_broadcast_t *) arg;
|
|
Packit |
eace71 |
if (do_ping)
|
|
Packit |
eace71 |
rec = &data->u.ping_rec.ifrec;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
rec = &data->u.iface_rec.rec;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "Received request for '%s' to set IP address: '%s' "
|
|
Packit |
eace71 |
"VLAN: '%d'",
|
|
Packit |
eace71 |
rec->netdev,
|
|
Packit |
eace71 |
rec->ipaddress,
|
|
Packit |
eace71 |
rec->vlan_id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = decode_iface(&ird, rec);
|
|
Packit |
eace71 |
if (ird.vlan_id && valid_vlan(ird.vlan_id) == 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Invalid VLAN tag: %d", ird.vlan_id);
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto early_exit;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (rc && !ird.ip_type) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "iface err: rc=%d, ip_type=%d", rc, ird.ip_type);
|
|
Packit |
eace71 |
goto early_exit;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < 10; i++) {
|
|
Packit |
eace71 |
struct timespec sleep_req, sleep_rem;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (pthread_mutex_trylock(&nic_list_mutex) == 0)
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sleep_req.tv_sec = 0;
|
|
Packit |
eace71 |
sleep_req.tv_nsec = 100000;
|
|
Packit |
eace71 |
nanosleep(&sleep_req, &sleep_rem);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i >= 10) {
|
|
Packit |
eace71 |
LOG_WARN(PFX "Could not acquire nic_list_mutex lock");
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto early_exit;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* nic_list_mutex locked */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Check if we can find the NIC device using the netdev
|
|
Packit |
eace71 |
* name */
|
|
Packit |
eace71 |
rc = from_netdev_name_find_nic(rec->netdev, &nic;;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_WARN(PFX "Couldn't find NIC: %s, creating an instance",
|
|
Packit |
eace71 |
rec->netdev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic = nic_init();
|
|
Packit |
eace71 |
if (nic == NULL) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Couldn't allocate space for NIC %s",
|
|
Packit |
eace71 |
rec->netdev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = -ENOMEM;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strncpy(nic->eth_device_name,
|
|
Packit |
eace71 |
rec->netdev,
|
|
Packit |
eace71 |
sizeof(nic->eth_device_name));
|
|
Packit |
eace71 |
nic->config_device_name = nic->eth_device_name;
|
|
Packit |
eace71 |
nic->log_name = nic->eth_device_name;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_fill_name(nic) != 0) {
|
|
Packit |
eace71 |
free(nic);
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_add(nic);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_INFO(PFX " %s, using existing NIC",
|
|
Packit |
eace71 |
rec->netdev);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
if (nic->flags & NIC_GOING_DOWN) {
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
LOG_INFO(PFX "nic->flags GOING DOWN");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* If we retry too many times allow iscsid to timeout */
|
|
Packit |
eace71 |
if (nic->pending_count > 1000) {
|
|
Packit |
eace71 |
nic->pending_count = 0;
|
|
Packit |
eace71 |
nic->flags &= ~NIC_ENABLED_PENDING;
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_WARN(PFX "%s: pending count exceeded 1000", nic->log_name);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic->flags & NIC_ENABLED_PENDING) {
|
|
Packit |
eace71 |
struct timespec sleep_req, sleep_rem;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic->pending_count++;
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sleep_req.tv_sec = 2;
|
|
Packit |
eace71 |
sleep_req.tv_nsec = 0;
|
|
Packit |
eace71 |
nanosleep(&sleep_req, &sleep_rem);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
if (!(nic->flags & NIC_ENABLED) ||
|
|
Packit |
eace71 |
nic->state != NIC_RUNNING) {
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: enabled pending", nic->log_name);
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
prepare_library(nic);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Sanity Check to ensure the transport names are the same */
|
|
Packit |
eace71 |
handle = nic->nic_library;
|
|
Packit |
eace71 |
if (handle != NULL) {
|
|
Packit |
eace71 |
(*handle->ops->lib_ops.get_transport_name) (&transport_name,
|
|
Packit |
eace71 |
&transport_name_size);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp(transport_name,
|
|
Packit |
eace71 |
rec->transport_name,
|
|
Packit |
eace71 |
transport_name_size) != 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "%s Transport name is not equal "
|
|
Packit |
eace71 |
"expected: %s got: %s",
|
|
Packit |
eace71 |
nic->log_name,
|
|
Packit |
eace71 |
rec->transport_name,
|
|
Packit |
eace71 |
transport_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_ERR(PFX "%s Couldn't find nic library ", nic->log_name);
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s library set using transport_name %s",
|
|
Packit |
eace71 |
nic->log_name, transport_name);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Determine how to configure the IP address */
|
|
Packit |
eace71 |
if (ird.ip_type == AF_INET) {
|
|
Packit |
eace71 |
if (memcmp(&ird.ipv4_addr,
|
|
Packit |
eace71 |
all_zeroes_addr4, sizeof(uip_ip4addr_t)) == 0) {
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: requesting configuration using DHCP",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
request_type = IPV4_CONFIG_DHCP;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: requesting configuration using "
|
|
Packit |
eace71 |
"static IP address", nic->log_name);
|
|
Packit |
eace71 |
request_type = IPV4_CONFIG_STATIC;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else if (ird.ip_type == AF_INET6) {
|
|
Packit |
eace71 |
/* For the new 872_22, check ipv6_autocfg for DHCPv6 instead */
|
|
Packit |
eace71 |
switch (ird.ipv6_autocfg) {
|
|
Packit |
eace71 |
case IPV6_AUTOCFG_DHCPV6:
|
|
Packit |
eace71 |
request_type = IPV6_CONFIG_DHCP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case IPV6_AUTOCFG_ND:
|
|
Packit |
eace71 |
request_type = IPV6_CONFIG_STATIC;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case IPV6_AUTOCFG_NOTSPEC:
|
|
Packit |
eace71 |
/* Treat NOTSPEC the same as NOTUSED for now */
|
|
Packit |
eace71 |
case IPV6_AUTOCFG_NOTUSED:
|
|
Packit |
eace71 |
/* For 871 */
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
/* Just the IP address to determine */
|
|
Packit |
eace71 |
if (memcmp(&ird.ipv6_addr,
|
|
Packit |
eace71 |
all_zeroes_addr6,
|
|
Packit |
eace71 |
sizeof(struct in6_addr)) == 0)
|
|
Packit |
eace71 |
request_type = IPV6_CONFIG_DHCP;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
request_type = IPV6_CONFIG_STATIC;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
LOG_ERR(PFX "%s: unknown ip_type to configure: 0x%x",
|
|
Packit |
eace71 |
nic->log_name, ird.ip_type);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = -EIO;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_iface = nic_find_nic_iface(nic, ird.ip_type, ird.vlan_id,
|
|
Packit |
eace71 |
ird.iface_num, request_type);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic->flags & NIC_PATHREQ_WAIT) {
|
|
Packit |
eace71 |
if (!nic_iface ||
|
|
Packit |
eace71 |
!(nic_iface->flags & NIC_IFACE_PATHREQ_WAIT)) {
|
|
Packit |
eace71 |
int pathreq_wait;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface &&
|
|
Packit |
eace71 |
(nic_iface->flags & NIC_IFACE_PATHREQ_WAIT2))
|
|
Packit |
eace71 |
pathreq_wait = 12;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
pathreq_wait = 10;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic->pathreq_pending_count < pathreq_wait) {
|
|
Packit |
eace71 |
struct timespec sleep_req, sleep_rem;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic->pathreq_pending_count++;
|
|
Packit |
eace71 |
sleep_req.tv_sec = 0;
|
|
Packit |
eace71 |
sleep_req.tv_nsec = 100000;
|
|
Packit |
eace71 |
nanosleep(&sleep_req, &sleep_rem);
|
|
Packit |
eace71 |
/* Somebody else is waiting for PATH_REQ */
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: path req pending cnt=%d",
|
|
Packit |
eace71 |
nic->log_name,
|
|
Packit |
eace71 |
nic->pathreq_pending_count);
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
nic->pathreq_pending_count = 0;
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "%s: path req pending cnt "
|
|
Packit |
eace71 |
"exceeded!", nic->log_name);
|
|
Packit |
eace71 |
/* Allow to fall thru */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic->flags |= NIC_PATHREQ_WAIT;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Create the network interface if it doesn't exist */
|
|
Packit |
eace71 |
if (nic_iface == NULL) {
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "%s couldn't find interface with "
|
|
Packit |
eace71 |
"ip_type: 0x%x creating it",
|
|
Packit |
eace71 |
nic->log_name, ird.ip_type);
|
|
Packit |
eace71 |
nic_iface = nic_iface_init();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface == NULL) {
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
LOG_ERR(PFX "%s Couldn't allocate "
|
|
Packit |
eace71 |
"interface with ip_type: 0x%x",
|
|
Packit |
eace71 |
nic->log_name, ird.ip_type);
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
nic_iface->protocol = ird.ip_type;
|
|
Packit |
eace71 |
nic_iface->vlan_id = ird.vlan_id;
|
|
Packit |
eace71 |
nic_iface->vlan_priority = ird.vlan_priority;
|
|
Packit |
eace71 |
if (ird.mtu >= MIN_MTU_SUPPORT && ird.mtu <= MAX_MTU_SUPPORT)
|
|
Packit |
eace71 |
nic_iface->mtu = ird.mtu;
|
|
Packit |
eace71 |
nic_iface->iface_num = ird.iface_num;
|
|
Packit |
eace71 |
nic_iface->request_type = request_type;
|
|
Packit |
eace71 |
nic_add_nic_iface(nic, nic_iface);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
persist_all_nic_iface(nic);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: created network interface",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* Move the nic_iface to the front */
|
|
Packit |
eace71 |
set_nic_iface(nic, nic_iface);
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: using existing network interface",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT1;
|
|
Packit |
eace71 |
if (nic->nl_process_thread == INVALID_THREAD) {
|
|
Packit |
eace71 |
pthread_attr_init(&attr);
|
|
Packit |
eace71 |
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
Packit |
eace71 |
rc = pthread_create(&nic->nl_process_thread, &attr,
|
|
Packit |
eace71 |
nl_process_handle_thread, nic);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "%s: Could not create NIC NL "
|
|
Packit |
eace71 |
"processing thread [%s]", nic->log_name,
|
|
Packit |
eace71 |
strerror(rc));
|
|
Packit |
eace71 |
nic->nl_process_thread = INVALID_THREAD;
|
|
Packit |
eace71 |
/* Reset both WAIT flags */
|
|
Packit |
eace71 |
nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT;
|
|
Packit |
eace71 |
nic->flags &= ~NIC_PATHREQ_WAIT;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic_iface->ustack.ip_config == request_type) {
|
|
Packit |
eace71 |
/* Same request_type, check for STATIC address change */
|
|
Packit |
eace71 |
if (request_type == IPV4_CONFIG_STATIC) {
|
|
Packit |
eace71 |
if (memcmp(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
|
|
Packit |
eace71 |
sizeof(struct in_addr)))
|
|
Packit |
eace71 |
goto reacquire;
|
|
Packit |
eace71 |
} else if (request_type == IPV6_CONFIG_STATIC) {
|
|
Packit |
eace71 |
if (memcmp(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
|
|
Packit |
eace71 |
sizeof(struct in6_addr)))
|
|
Packit |
eace71 |
goto reacquire;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, &ird.ipv6_addr,
|
|
Packit |
eace71 |
ipv6_buf_str,
|
|
Packit |
eace71 |
sizeof(ipv6_buf_str));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: IP configuration didn't change using 0x%x",
|
|
Packit |
eace71 |
nic->log_name, nic_iface->ustack.ip_config);
|
|
Packit |
eace71 |
/* No need to acquire the IP address */
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
Packit |
eace71 |
sizeof(ipv6_buf_str));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
goto enable_nic;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
reacquire:
|
|
Packit |
eace71 |
/* Config needs to re-acquire for this nic_iface */
|
|
Packit |
eace71 |
pthread_mutex_lock(&nic->nic_mutex);
|
|
Packit |
eace71 |
nic_iface->flags |= NIC_IFACE_ACQUIRE;
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic->nic_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Disable the nic loop from further processing, upon returned,
|
|
Packit |
eace71 |
the nic_iface should be cleared */
|
|
Packit |
eace71 |
nic_disable(nic, 0);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Check to see if this is using DHCP or if this is
|
|
Packit |
eace71 |
* a static IPv4 address. This is done by checking
|
|
Packit |
eace71 |
* if the IP address is equal to 0.0.0.0. If it is
|
|
Packit |
eace71 |
* then the user has specified to use DHCP. If not
|
|
Packit |
eace71 |
* then the user has spcicied to use a static IP address
|
|
Packit |
eace71 |
* an the default netmask will be used */
|
|
Packit |
eace71 |
switch (request_type) {
|
|
Packit |
eace71 |
case IPV4_CONFIG_DHCP:
|
|
Packit |
eace71 |
memset(nic_iface->ustack.hostaddr, 0, sizeof(struct in_addr));
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: configuring using DHCP", nic->log_name);
|
|
Packit |
eace71 |
nic_iface->ustack.ip_config = IPV4_CONFIG_DHCP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
case IPV4_CONFIG_STATIC:
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
|
|
Packit |
eace71 |
sizeof(struct in_addr));
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: configuring using static IP "
|
|
Packit |
eace71 |
"IPv4 address :%s ",
|
|
Packit |
eace71 |
nic->log_name, inet_ntoa(ird.ipv4_addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ird.ipv4_subnet_mask.s_addr)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.netmask,
|
|
Packit |
eace71 |
&ird.ipv4_subnet_mask, sizeof(struct in_addr));
|
|
Packit |
eace71 |
LOG_INFO(PFX " netmask: %s", inet_ntoa(ird.ipv4_subnet_mask));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Default route */
|
|
Packit |
eace71 |
if (ird.ipv4_gateway.s_addr) {
|
|
Packit |
eace71 |
/* Check for validity */
|
|
Packit |
eace71 |
src_match.s_addr = ird.ipv4_addr.s_addr &
|
|
Packit |
eace71 |
ird.ipv4_subnet_mask.s_addr;
|
|
Packit |
eace71 |
dst_match.s_addr = ird.ipv4_gateway.s_addr &
|
|
Packit |
eace71 |
ird.ipv4_subnet_mask.s_addr;
|
|
Packit |
eace71 |
if (src_match.s_addr == dst_match.s_addr)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.default_route_addr,
|
|
Packit |
eace71 |
&ird.ipv4_gateway,
|
|
Packit |
eace71 |
sizeof(struct in_addr));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
nic_iface->ustack.ip_config = IPV4_CONFIG_STATIC;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
case IPV6_CONFIG_DHCP:
|
|
Packit |
eace71 |
memset(nic_iface->ustack.hostaddr6, 0,
|
|
Packit |
eace71 |
sizeof(struct in6_addr));
|
|
Packit |
eace71 |
nic_iface->ustack.prefix_len = ird.prefix_len;
|
|
Packit |
eace71 |
nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
|
|
Packit |
eace71 |
nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
|
|
Packit |
eace71 |
nic_iface->ustack.router_autocfg = ird.router_autocfg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
|
|
Packit |
eace71 |
sizeof(struct in6_addr)))
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.netmask6,
|
|
Packit |
eace71 |
&ird.ipv6_subnet_mask, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.linklocal6,
|
|
Packit |
eace71 |
&ird.ipv6_linklocal, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.default_route_addr6,
|
|
Packit |
eace71 |
&ird.ipv6_router, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
Packit |
eace71 |
sizeof(ipv6_buf_str));
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: configuring using DHCPv6",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
nic_iface->ustack.ip_config = IPV6_CONFIG_DHCP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
case IPV6_CONFIG_STATIC:
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
|
|
Packit |
eace71 |
sizeof(struct in6_addr));
|
|
Packit |
eace71 |
nic_iface->ustack.prefix_len = ird.prefix_len;
|
|
Packit |
eace71 |
nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
|
|
Packit |
eace71 |
nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
|
|
Packit |
eace71 |
nic_iface->ustack.router_autocfg = ird.router_autocfg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
|
|
Packit |
eace71 |
sizeof(struct in6_addr)))
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.netmask6,
|
|
Packit |
eace71 |
&ird.ipv6_subnet_mask, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.linklocal6,
|
|
Packit |
eace71 |
&ird.ipv6_linklocal, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
|
|
Packit |
eace71 |
memcpy(nic_iface->ustack.default_route_addr6,
|
|
Packit |
eace71 |
&ird.ipv6_router, sizeof(struct in6_addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
Packit |
eace71 |
sizeof(ipv6_buf_str));
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: configuring using static IP "
|
|
Packit |
eace71 |
"IPv6 address: '%s'", nic->log_name, ipv6_buf_str);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_iface->ustack.ip_config = IPV6_CONFIG_STATIC;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: Unknown request type: 0x%x",
|
|
Packit |
eace71 |
nic->log_name, request_type);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
enable_nic:
|
|
Packit |
eace71 |
switch (nic->state) {
|
|
Packit |
eace71 |
case NIC_STOPPED:
|
|
Packit |
eace71 |
/* This thread will be thrown away when completed */
|
|
Packit |
eace71 |
if (nic->enable_thread != INVALID_THREAD) {
|
|
Packit |
eace71 |
rc = pthread_cancel(nic->enable_thread);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: failed to cancel enable NIC "
|
|
Packit |
eace71 |
"thread\n", nic->log_name);
|
|
Packit |
eace71 |
goto eagain;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
pthread_attr_init(&attr);
|
|
Packit |
eace71 |
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
Packit |
eace71 |
rc = pthread_create(&nic->enable_thread, &attr,
|
|
Packit |
eace71 |
enable_nic_thread, (void *)nic);
|
|
Packit |
eace71 |
if (rc != 0)
|
|
Packit |
eace71 |
LOG_WARN(PFX "%s: failed starting enable NIC thread\n",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
eagain:
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
case NIC_RUNNING:
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: NIC already enabled "
|
|
Packit |
eace71 |
"flags: 0x%x state: 0x%x\n",
|
|
Packit |
eace71 |
nic->log_name, nic->flags, nic->state);
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: NIC enable still in progress "
|
|
Packit |
eace71 |
"flags: 0x%x state: 0x%x\n",
|
|
Packit |
eace71 |
nic->log_name, nic->flags, nic->state);
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "ISCSID_UIP_IPC_GET_IFACE: command: %x "
|
|
Packit |
eace71 |
"name: %s, netdev: %s ipaddr: %s vlan: %d transport_name:%s",
|
|
Packit |
eace71 |
data->header.command, rec->name, rec->netdev,
|
|
Packit |
eace71 |
(ird.ip_type == AF_INET) ? inet_ntoa(ird.ipv4_addr) :
|
|
Packit |
eace71 |
ipv6_buf_str,
|
|
Packit |
eace71 |
ird.vlan_id, rec->transport_name);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (do_ping) {
|
|
Packit |
eace71 |
if (nic->ping_thread != INVALID_THREAD) {
|
|
Packit |
eace71 |
rc = pthread_cancel(nic->ping_thread);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_INFO(PFX "%s: failed to cancel ping thread",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
png_c = malloc(sizeof(struct ping_conf));
|
|
Packit |
eace71 |
if (!png_c) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Memory alloc failed for ping conf");
|
|
Packit |
eace71 |
rc = -ENOMEM;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(png_c, 0, sizeof(struct ping_conf));
|
|
Packit |
eace71 |
png_c->nic_iface = nic_iface;
|
|
Packit |
eace71 |
png_c->data = arg;
|
|
Packit |
eace71 |
nic_iface->ustack.ping_conf = png_c;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Spawn a thread to perform ping operation.
|
|
Packit |
eace71 |
* This thread will exit when done.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
rc = pthread_create(&nic->ping_thread, NULL,
|
|
Packit |
eace71 |
perform_ping, (void *)png_c);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_WARN(PFX "%s: failed starting ping thread\n",
|
|
Packit |
eace71 |
nic->log_name);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
pthread_join(nic->ping_thread, NULL);
|
|
Packit |
eace71 |
rc = png_c->state;
|
|
Packit |
eace71 |
if (rc == -EAGAIN)
|
|
Packit |
eace71 |
png_c->state = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free(png_c);
|
|
Packit |
eace71 |
nic_iface->ustack.ping_conf = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
pthread_mutex_unlock(&nic_list_mutex);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
early_exit:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* process_iscsid_broadcast() - This function is used to process the
|
|
Packit |
eace71 |
* broadcast messages from iscsid
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* s2 is an open file descriptor, which
|
|
Packit |
eace71 |
* must not be left open upon return
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int process_iscsid_broadcast(int s2)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
iscsid_uip_broadcast_t *data;
|
|
Packit |
eace71 |
iscsid_uip_rsp_t rsp;
|
|
Packit |
eace71 |
FILE *fd;
|
|
Packit |
eace71 |
size_t size;
|
|
Packit |
eace71 |
iscsid_uip_cmd_e cmd;
|
|
Packit |
eace71 |
uint32_t payload_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fd = fdopen(s2, "r+");
|
|
Packit |
eace71 |
if (fd == NULL) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Couldn't open file descriptor: %d(%s)",
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
close(s2);
|
|
Packit |
eace71 |
return -EIO;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* This will be freed by parse_iface_thread() */
|
|
Packit |
eace71 |
data = (iscsid_uip_broadcast_t *) calloc(1, sizeof(*data));
|
|
Packit |
eace71 |
if (data == NULL) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Couldn't allocate memory for iface data");
|
|
Packit |
eace71 |
rc = -ENOMEM;
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memset(data, 0, sizeof(*data));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
size = fread(data, sizeof(iscsid_uip_broadcast_header_t), 1, fd);
|
|
Packit |
eace71 |
if (!size) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not read request: %d(%s)",
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
rc = ferror(fd);
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
cmd = data->header.command;
|
|
Packit |
eace71 |
payload_len = data->header.payload_len;
|
|
Packit |
eace71 |
if (payload_len > sizeof(data->u)) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Data payload length too large (%d). Corrupt payload?",
|
|
Packit |
eace71 |
payload_len);
|
|
Packit |
eace71 |
rc = -EINVAL;
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "recv iscsid request: cmd: %d, payload_len: %d",
|
|
Packit |
eace71 |
cmd, payload_len);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&rsp, 0, sizeof(rsp));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (cmd) {
|
|
Packit |
eace71 |
case ISCSID_UIP_IPC_GET_IFACE:
|
|
Packit |
eace71 |
size = fread(&data->u.iface_rec, payload_len, 1, fd);
|
|
Packit |
eace71 |
if (!size) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not read data: %d(%s)",
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = parse_iface(data, 0);
|
|
Packit |
eace71 |
switch (rc) {
|
|
Packit |
eace71 |
case 0:
|
|
Packit |
eace71 |
rsp.command = cmd;
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case -EAGAIN:
|
|
Packit |
eace71 |
rsp.command = cmd;
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
rsp.command = cmd;
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSID_UIP_IPC_PING:
|
|
Packit |
eace71 |
size = fread(&data->u.ping_rec, payload_len, 1, fd);
|
|
Packit |
eace71 |
if (!size) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not read data: %d(%s)",
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = parse_iface(data, 1);
|
|
Packit |
eace71 |
rsp.command = cmd;
|
|
Packit |
eace71 |
rsp.ping_sc = rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (rc) {
|
|
Packit |
eace71 |
case 0:
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case -EAGAIN:
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
LOG_WARN(PFX "Unknown iscsid broadcast command: %x",
|
|
Packit |
eace71 |
data->header.command);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Send a response back to iscsid to tell it the
|
|
Packit |
eace71 |
operation succeeded */
|
|
Packit |
eace71 |
rsp.command = cmd;
|
|
Packit |
eace71 |
rsp.err = ISCSID_UIP_MGMT_IPC_OK;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
size = fwrite(&rsp, sizeof(rsp), 1, fd);
|
|
Packit |
eace71 |
if (size == -1) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not send response: %d(%s)",
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
rc = ferror(fd);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
error:
|
|
Packit |
eace71 |
if (data)
|
|
Packit |
eace71 |
free(data);
|
|
Packit |
eace71 |
fclose(fd);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void iscsid_loop_close(void *arg)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
close(iscsid_opts.fd);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "iSCSI daemon socket closed");
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* check that the peer user is privilidged
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* return 1 if peer is ok else 0
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* XXX: this function is copied from iscsid_ipc.c and should be
|
|
Packit |
eace71 |
* moved into a common library
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
mgmt_peeruser(int sock, char *user)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct ucred peercred;
|
|
Packit |
eace71 |
socklen_t so_len = sizeof(peercred);
|
|
Packit |
eace71 |
struct passwd *pass;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
errno = 0;
|
|
Packit |
eace71 |
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred,
|
|
Packit |
eace71 |
&so_len) != 0 || so_len != sizeof(peercred)) {
|
|
Packit |
eace71 |
/* We didn't get a valid credentials struct. */
|
|
Packit |
eace71 |
LOG_ERR(PFX "peeruser_unux: error receiving credentials: %m");
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pass = getpwuid(peercred.uid);
|
|
Packit |
eace71 |
if (pass == NULL) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "peeruser_unix: unknown local user with uid %d",
|
|
Packit |
eace71 |
(int) peercred.uid);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(user, pass->pw_name, PEERUSER_MAX);
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsid_loop() - This is the function which will process the broadcast
|
|
Packit |
eace71 |
* messages from iscsid
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static void *iscsid_loop(void *arg)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
sigset_t set;
|
|
Packit |
eace71 |
char user[PEERUSER_MAX];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_cleanup_push(iscsid_loop_close, arg);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sigfillset(&set);
|
|
Packit |
eace71 |
rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX
|
|
Packit |
eace71 |
"Couldn't set signal mask for the iscisd listening "
|
|
Packit |
eace71 |
"thread");
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Started iscsid listening thread");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (1) {
|
|
Packit |
eace71 |
struct sockaddr_un remote;
|
|
Packit |
eace71 |
socklen_t sock_len;
|
|
Packit |
eace71 |
int s2;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX "Waiting for iscsid command");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sock_len = sizeof(remote);
|
|
Packit |
eace71 |
s2 = accept(iscsid_opts.fd,
|
|
Packit |
eace71 |
(struct sockaddr *)&remote, &sock_len);
|
|
Packit |
eace71 |
if (s2 == -1) {
|
|
Packit |
eace71 |
if (errno == EAGAIN) {
|
|
Packit |
eace71 |
LOG_DEBUG("Got EAGAIN from accept");
|
|
Packit |
eace71 |
sleep(1);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
} else if (errno == EINTR) {
|
|
Packit |
eace71 |
LOG_DEBUG("Got EINTR from accept");
|
|
Packit |
eace71 |
/* The program is terminating, time to exit */
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not accept: %d(%s)",
|
|
Packit |
eace71 |
s2, strerror(errno));
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!mgmt_peeruser(iscsid_opts.fd, user) || strncmp(user, "root", PEERUSER_MAX)) {
|
|
Packit |
eace71 |
close(s2);
|
|
Packit |
eace71 |
LOG_ERR(PFX "Access error: non-administrative connection rejected");
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* this closes the file descriptor s2 */
|
|
Packit |
eace71 |
process_iscsid_broadcast(s2);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_cleanup_pop(0);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_ERR(PFX "exit iscsid listening thread");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_exit(NULL);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define SD_SOCKET_FDS_START 3
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int ipc_systemd(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char *env;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
env = getenv("LISTEN_PID");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!env || (strtoul(env, NULL, 10) != getpid()))
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
env = getenv("LISTEN_FDS");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!env)
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strtoul(env, NULL, 10) != 1) {
|
|
Packit |
eace71 |
LOG_ERR("Did not receive exactly one IPC socket from systemd");
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return SD_SOCKET_FDS_START;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/******************************************************************************
|
|
Packit |
eace71 |
* Initialize/Cleanup routines
|
|
Packit |
eace71 |
******************************************************************************/
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsid_init() - This function will setup the thread used to listen for
|
|
Packit |
eace71 |
* the iscsid broadcast messages
|
|
Packit |
eace71 |
* @return 0 on success, <0 on failure
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsid_init()
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, addr_len;
|
|
Packit |
eace71 |
struct sockaddr_un addr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iscsid_opts.fd = ipc_systemd();
|
|
Packit |
eace71 |
if (iscsid_opts.fd >= 0)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
Packit |
eace71 |
if (iscsid_opts.fd < 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Can not create IPC socket");
|
|
Packit |
eace71 |
return iscsid_opts.fd;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(ISCSID_UIP_NAMESPACE) + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&addr, 0, sizeof(addr));
|
|
Packit |
eace71 |
addr.sun_family = AF_LOCAL;
|
|
Packit |
eace71 |
memcpy((char *)&addr.sun_path + 1, ISCSID_UIP_NAMESPACE,
|
|
Packit |
eace71 |
strlen(ISCSID_UIP_NAMESPACE));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = bind(iscsid_opts.fd, (struct sockaddr *)&addr, addr_len);
|
|
Packit |
eace71 |
if (rc < 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Can not bind IPC socket: %s", strerror(errno));
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = listen(iscsid_opts.fd, 32);
|
|
Packit |
eace71 |
if (rc < 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Can not listen IPC socket: %s", strerror(errno));
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
error:
|
|
Packit |
eace71 |
close(iscsid_opts.fd);
|
|
Packit |
eace71 |
iscsid_opts.fd = INVALID_FD;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsid_start() - This function will start the thread used to listen for
|
|
Packit |
eace71 |
* the iscsid broadcast messages
|
|
Packit |
eace71 |
* @return 0 on success, <0 on failure
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsid_start()
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
pthread_attr_t attr;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_attr_init(&attr);
|
|
Packit |
eace71 |
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
Packit |
eace71 |
rc = pthread_create(&iscsid_opts.thread, &attr, iscsid_loop, NULL);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_ERR(PFX "Could not start iscsid listening thread rc=%d",
|
|
Packit |
eace71 |
rc);
|
|
Packit |
eace71 |
goto error;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
error:
|
|
Packit |
eace71 |
close(iscsid_opts.fd);
|
|
Packit |
eace71 |
iscsid_opts.fd = INVALID_FD;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsid_cleanup() - This is called when stoping the thread listening
|
|
Packit |
eace71 |
* for the iscsid broadcast messages
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
void iscsid_cleanup()
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iscsid_opts.fd != INVALID_FD &&
|
|
Packit |
eace71 |
iscsid_opts.thread != INVALID_THREAD) {
|
|
Packit |
eace71 |
rc = pthread_cancel(iscsid_opts.thread);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
LOG_ERR("Could not cancel iscsid listening thread: %s",
|
|
Packit |
eace71 |
strerror(rc));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_INFO(PFX "iscsid listening thread has shutdown");
|
|
Packit |
eace71 |
}
|