Blame ctrl_iface.c

Packit 597cd4
/*******************************************************************************
Packit 597cd4
Packit 597cd4
  LLDP Agent Daemon (LLDPAD) Software
Packit 597cd4
  Copyright(c) 2007-2010 Intel Corporation.
Packit 597cd4
Packit 597cd4
  Substantially modified from:
Packit 597cd4
  hostapd-0.5.7
Packit 597cd4
  Copyright (c) 2002-2007, Jouni Malinen <jkmaline@cc.hut.fi> and
Packit 597cd4
  contributors
Packit 597cd4
Packit 597cd4
  This program is free software; you can redistribute it and/or modify it
Packit 597cd4
  under the terms and conditions of the GNU General Public License,
Packit 597cd4
  version 2, as published by the Free Software Foundation.
Packit 597cd4
Packit 597cd4
  This program is distributed in the hope it will be useful, but WITHOUT
Packit 597cd4
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 597cd4
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit 597cd4
  more details.
Packit 597cd4
Packit 597cd4
  You should have received a copy of the GNU General Public License along with
Packit 597cd4
  this program; if not, write to the Free Software Foundation, Inc.,
Packit 597cd4
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit 597cd4
Packit 597cd4
  The full GNU General Public License is included in this distribution in
Packit 597cd4
  the file called "COPYING".
Packit 597cd4
Packit 597cd4
  Contact Information:
Packit 597cd4
  open-lldp Mailing List <lldp-devel@open-lldp.org>
Packit 597cd4
Packit 597cd4
*******************************************************************************/
Packit 597cd4
Packit 597cd4
#define _GNU_SOURCE
Packit 597cd4
Packit 597cd4
#include <stdlib.h>
Packit 597cd4
#include <string.h>
Packit 597cd4
#include <sys/un.h>
Packit 597cd4
#include <sys/stat.h>
Packit 597cd4
#include <sys/queue.h>
Packit 597cd4
#include <sys/socket.h>
Packit 597cd4
#include <errno.h>
Packit 597cd4
#include <stdio.h>
Packit 597cd4
#include <unistd.h>
Packit 597cd4
#include "lldpad.h"
Packit 597cd4
#include "eloop.h"
Packit 597cd4
#include "ctrl_iface.h"
Packit 597cd4
#include "dcb_protocol.h"
Packit 597cd4
#include "list.h"
Packit 597cd4
#include "lldp_mod.h"
Packit 597cd4
#include "clif_msgs.h"
Packit 597cd4
#include "lldpad_status.h"
Packit 597cd4
#include "lldp/ports.h"
Packit 597cd4
#include "lldp_dcbx.h"
Packit 597cd4
#include "lldp_util.h"
Packit 597cd4
#include "messages.h"
Packit 597cd4
Packit 597cd4
extern struct lldp_head lldp_head;
Packit 597cd4
Packit 597cd4
struct ctrl_dst {
Packit 597cd4
	struct ctrl_dst *next;
Packit 597cd4
	struct sockaddr_un addr;
Packit 597cd4
	socklen_t addrlen;
Packit 597cd4
	int debug_level;
Packit 597cd4
	int errors;
Packit 597cd4
	u32 *tlv_types; /*tlv event types to recv */
Packit 597cd4
};
Packit 597cd4
Packit 597cd4
static char *hexlist = "0123456789abcdef";
Packit 597cd4
Packit 597cd4
struct clif_cmds {
Packit 597cd4
	int cmd;
Packit 597cd4
	int (*cmd_handler)(struct clif_data *cd,
Packit 597cd4
			   struct sockaddr_un *from,
Packit 597cd4
			   socklen_t fromlen,
Packit 597cd4
			   char *ibuf, int ilen,
Packit 597cd4
			   char *rbuf, int rlen);
Packit 597cd4
};
Packit 597cd4
Packit 597cd4
static const struct clif_cmds cmd_tbl[] = {
Packit 597cd4
	{ DCB_CMD,     clif_iface_module },
Packit 597cd4
	{ MOD_CMD,     clif_iface_module },
Packit 597cd4
	{ ATTACH_CMD,  clif_iface_attach },
Packit 597cd4
	{ DETACH_CMD,  clif_iface_detach },
Packit 597cd4
	{ LEVEL_CMD,   clif_iface_level },
Packit 597cd4
	{ PING_CMD,    clif_iface_ping },
Packit 597cd4
	{ UNKNOWN_CMD, clif_iface_cmd_unknown }
Packit 597cd4
};
Packit 597cd4
Packit 597cd4
int clif_iface_module(struct clif_data *clifd,
Packit 597cd4
		      struct sockaddr_un *from,
Packit 597cd4
		      socklen_t fromlen,
Packit 597cd4
		      char *ibuf, int ilen,
Packit 597cd4
		      char *rbuf, int rlen)
Packit 597cd4
{
Packit 597cd4
	u32 module_id;
Packit 597cd4
	char *cmd_start;
Packit 597cd4
	int cmd_len;
Packit 597cd4
	struct lldp_module *mod = NULL;
Packit 597cd4
Packit 597cd4
	/* identify the module and start of command */
Packit 597cd4
	switch (*ibuf) {
Packit 597cd4
	case DCB_CMD:
Packit 597cd4
		/* Message does not contain a module id, therefore this
Packit 597cd4
		 * message is a DCBX message.  Set module_id to correct value.
Packit 597cd4
		 */
Packit 597cd4
		module_id = 0x001b2101;
Packit 597cd4
		cmd_start = ibuf;
Packit 597cd4
		cmd_len = ilen;
Packit 597cd4
		break;
Packit 597cd4
	case MOD_CMD:
Packit 597cd4
		hexstr2bin(ibuf+MOD_ID, (u8 *)&module_id, sizeof(module_id));
Packit 597cd4
		module_id = ntohl(module_id);
Packit 597cd4
		cmd_start = ibuf + MOD_ID + 2*sizeof(module_id);
Packit 597cd4
		cmd_len = ilen - MOD_ID - 2*sizeof(module_id);
Packit 597cd4
		break;
Packit 597cd4
	default:
Packit 597cd4
		return cmd_invalid;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	mod = find_module_by_id(&lldp_head, module_id);
Packit 597cd4
	if (mod && mod->ops && mod->ops->client_cmd)
Packit 597cd4
		return  (mod->ops->client_cmd)(clifd, from, fromlen,
Packit 597cd4
			 cmd_start, cmd_len, rbuf+strlen(rbuf), rlen);
Packit 597cd4
	else
Packit 597cd4
		return cmd_device_not_found;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
Packit 597cd4
int clif_iface_cmd_unknown(UNUSED struct clif_data *clifd,
Packit 597cd4
			   UNUSED struct sockaddr_un *from,
Packit 597cd4
			   UNUSED socklen_t fromlen,
Packit 597cd4
			   UNUSED char *ibuf, UNUSED int ilen,
Packit 597cd4
			   UNUSED char *rbuf, UNUSED int rlen)
Packit 597cd4
{
Packit 597cd4
	return cmd_invalid;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int clif_iface_ping(UNUSED struct clif_data *clifd,
Packit 597cd4
		    UNUSED struct sockaddr_un *from,
Packit 597cd4
		    UNUSED socklen_t fromlen,
Packit 597cd4
		    UNUSED char *ibuf, UNUSED int ilen,
Packit 597cd4
		    char *rbuf, int rlen)
Packit 597cd4
{
Packit 597cd4
	snprintf(rbuf, rlen, "%cPONG%d", PING_CMD, getpid());
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int clif_iface_attach(struct clif_data *clifd,
Packit 597cd4
		      struct sockaddr_un *from,
Packit 597cd4
		      socklen_t fromlen,
Packit 597cd4
		      char *ibuf, UNUSED int ilen,
Packit 597cd4
		      char *rbuf, int rlen)
Packit 597cd4
{
Packit 597cd4
	struct ctrl_dst *dst;
Packit 597cd4
	char *tlv, *str, *tokenize;
Packit 597cd4
	const char *delim = ",";
Packit 597cd4
	int i, tlv_count = 0;
Packit 597cd4
Packit 597cd4
	dst = malloc(sizeof(*dst));
Packit 597cd4
	if (dst == NULL)
Packit 597cd4
		return cmd_failed;
Packit 597cd4
	memset(dst, 0, sizeof(*dst));
Packit 597cd4
	memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
Packit 597cd4
	dst->addrlen = fromlen;
Packit 597cd4
	dst->debug_level = MSG_INFO;
Packit 597cd4
Packit 597cd4
	/*
Packit 597cd4
	 * There are two cases here one, the user provided
Packit 597cd4
	 * no string in which case we must send DCBX events
Packit 597cd4
	 * to be compatible with legacy clients. Two the
Packit 597cd4
	 * user sent a comma seperated string of tlv module
Packit 597cd4
	 * ids it expects events from
Packit 597cd4
	 */
Packit 597cd4
	/* set default string to DCBX Events */
Packit 597cd4
	if (ibuf[1] == '\0') {
Packit 597cd4
		u32 hex = LLDP_MOD_DCBX;
Packit 597cd4
		tlv = malloc(sizeof(char) * (8 + 2));
Packit 597cd4
		if (!tlv)
Packit 597cd4
			goto err_tlv;
Packit 597cd4
		tlv[0] = 'A';
Packit 597cd4
		tlv[9] = 0;
Packit 597cd4
		bin2hexstr((u8*)&hex, 4, &tlv[1], 8);
Packit 597cd4
	} else
Packit 597cd4
		tlv = strdup(ibuf);
Packit 597cd4
Packit 597cd4
	str = tlv;
Packit 597cd4
	str++;
Packit 597cd4
	/* Count number of TLV Modules */
Packit 597cd4
	tokenize = strtok(str, delim);
Packit 597cd4
	tlv_count++;
Packit 597cd4
	do {
Packit 597cd4
		tokenize = strtok(NULL, delim);
Packit 597cd4
		tlv_count++;
Packit 597cd4
	} while (tokenize);
Packit 597cd4
Packit 597cd4
	dst->tlv_types = malloc(sizeof(u32) * tlv_count);
Packit 597cd4
	if (!dst->tlv_types)
Packit 597cd4
		goto err_types;
Packit 597cd4
	memset(dst->tlv_types, 0, sizeof(u32) * tlv_count);
Packit 597cd4
Packit 597cd4
	/* Populate tlv_types from comma separated string */
Packit 597cd4
	tokenize = strtok(str, delim);
Packit 597cd4
	for (i=0; tokenize; i++) {
Packit 597cd4
		char *myend;
Packit 597cd4
Packit 597cd4
		dst->tlv_types[i] = strtol(tokenize, &myend, 16);
Packit 597cd4
		if (*myend)		/* No hexnumber for module id */
Packit 597cd4
			goto err_types;
Packit 597cd4
		tokenize = strtok(NULL, delim);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Insert Termination Pattern */
Packit 597cd4
	dst->tlv_types[i] = ~0;
Packit 597cd4
	free(tlv);
Packit 597cd4
Packit 597cd4
	/* Insert new node at beginning */
Packit 597cd4
	dst->next = clifd->ctrl_dst;
Packit 597cd4
	clifd->ctrl_dst = dst;
Packit 597cd4
	LLDPAD_DBG("CTRL_IFACE monitor attached\n");
Packit 597cd4
	snprintf(rbuf, rlen, "%c", ATTACH_CMD);
Packit 597cd4
Packit 597cd4
	return cmd_success;
Packit 597cd4
err_types:
Packit 597cd4
	free(tlv);
Packit 597cd4
err_tlv:
Packit 597cd4
	free(dst);
Packit 597cd4
	LLDPAD_DBG("CTRL_IFACE monitor attach error\n");
Packit 597cd4
	snprintf(rbuf, rlen, "%c", ATTACH_CMD);
Packit 597cd4
Packit 597cd4
	return cmd_failed;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int detach_clif_monitor(struct clif_data *clifd,
Packit 597cd4
				     struct sockaddr_un *from,
Packit 597cd4
				     socklen_t fromlen)
Packit 597cd4
{
Packit 597cd4
	struct ctrl_dst *dst, *prev = NULL;
Packit 597cd4
Packit 597cd4
	dst = clifd->ctrl_dst;
Packit 597cd4
	while (dst) {
Packit 597cd4
		if (fromlen == dst->addrlen &&
Packit 597cd4
		    memcmp(from->sun_path, dst->addr.sun_path,
Packit 597cd4
			fromlen-sizeof(from->sun_family)) == 0) {
Packit 597cd4
			if (prev == NULL)
Packit 597cd4
				clifd->ctrl_dst = dst->next;
Packit 597cd4
			else
Packit 597cd4
				prev->next = dst->next;
Packit 597cd4
			free(dst->tlv_types);
Packit 597cd4
			free(dst);
Packit 597cd4
			dst = NULL;
Packit 597cd4
			LLDPAD_DBG("CTRL_IFACE monitor detached\n");
Packit 597cd4
Packit 597cd4
			return 0;
Packit 597cd4
		}
Packit 597cd4
		prev = dst;
Packit 597cd4
		dst = dst->next;
Packit 597cd4
	}
Packit 597cd4
	return cmd_failed;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int clif_iface_detach(struct clif_data *clifd,
Packit 597cd4
				     struct sockaddr_un *from,
Packit 597cd4
				     socklen_t fromlen,
Packit 597cd4
				     UNUSED char *ibuf, UNUSED int ilen,
Packit 597cd4
				     char *rbuf, int rlen)
Packit 597cd4
{
Packit 597cd4
	snprintf(rbuf, rlen, "%c", DETACH_CMD);
Packit 597cd4
	return detach_clif_monitor(clifd, from, fromlen);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int clif_iface_level(struct clif_data *clifd,
Packit 597cd4
				    struct sockaddr_un *from,
Packit 597cd4
				    socklen_t fromlen,
Packit 597cd4
				    char *ibuf, UNUSED int ilen,
Packit 597cd4
				    char *rbuf, int rlen)
Packit 597cd4
{
Packit 597cd4
	struct ctrl_dst *dst;
Packit 597cd4
	char *level;
Packit 597cd4
Packit 597cd4
	level = ibuf+1;
Packit 597cd4
	snprintf(rbuf, rlen, "%c", LEVEL_CMD);
Packit 597cd4
Packit 597cd4
	LLDPAD_DBG("CTRL_IFACE LEVEL %s\n", level);
Packit 597cd4
Packit 597cd4
	dst = clifd->ctrl_dst;
Packit 597cd4
	while (dst) {
Packit 597cd4
		if (fromlen == dst->addrlen &&
Packit 597cd4
		    memcmp(from->sun_path, dst->addr.sun_path,
Packit 597cd4
			fromlen-sizeof(from->sun_family)) == 0) {
Packit 597cd4
			LLDPAD_DBG("CTRL_IFACE changed monitor level\n");
Packit 597cd4
Packit 597cd4
			return 0;
Packit 597cd4
		}
Packit 597cd4
		dst = dst->next;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return cmd_failed;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int find_cmd_entry(int cmd)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	for (i = 0; cmd_tbl[i].cmd != cmd && cmd_tbl[i].cmd != UNKNOWN_CMD; i++)
Packit 597cd4
		;
Packit 597cd4
Packit 597cd4
	return (i);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/* process_clif_cmd - routine to pass command to correct module routine and
Packit 597cd4
 *		      compute length and status.
Packit 597cd4
 *
Packit 597cd4
 * Note: ibuf and ilen must be verified by caller.
Packit 597cd4
 */
Packit 597cd4
static void process_clif_cmd(  struct clif_data *cd,
Packit 597cd4
			struct sockaddr_un *from,
Packit 597cd4
			socklen_t fromlen,
Packit 597cd4
			char *ibuf, int ilen, char *rbuf, int rsize, int *rlen)
Packit 597cd4
{
Packit 597cd4
	int status;
Packit 597cd4
Packit 597cd4
	/* setup minimum command response message
Packit 597cd4
	 * status will be updated at end */
Packit 597cd4
	snprintf(rbuf, rsize, "%c%02x", CMD_RESPONSE, cmd_failed);
Packit 597cd4
	status = cmd_tbl[find_cmd_entry((int)ibuf[0])].cmd_handler(
Packit 597cd4
					 cd, from, fromlen, ibuf, ilen,
Packit 597cd4
					 rbuf + strlen(rbuf),
Packit 597cd4
					 rsize - strlen(rbuf) - 1);
Packit 597cd4
Packit 597cd4
	/* update status and compute final length */
Packit 597cd4
	rbuf[CLIF_STAT_OFF] = hexlist[(status & 0xf0) >> 4];
Packit 597cd4
	rbuf[CLIF_STAT_OFF+1] = hexlist[status & 0x0f];
Packit 597cd4
	*rlen = strlen(rbuf);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
Packit 597cd4
static void ctrl_iface_receive(int sock, void *eloop_ctx,
Packit 597cd4
			       UNUSED void *sock_ctx)
Packit 597cd4
{
Packit 597cd4
	struct clif_data *clifd = eloop_ctx;
Packit 597cd4
	char buf[MAX_CLIF_MSGBUF];
Packit 597cd4
	struct msghdr smsg;
Packit 597cd4
	struct cmsghdr *cmsg;
Packit 597cd4
	struct iovec iov;
Packit 597cd4
	struct ucred *cred;
Packit 597cd4
	char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
Packit 597cd4
	int res;
Packit 597cd4
	struct sockaddr_un from;
Packit 597cd4
	socklen_t fromlen = sizeof(from);
Packit 597cd4
	char *reply;
Packit 597cd4
	const int reply_size = MAX_CLIF_MSGBUF;
Packit 597cd4
	int reply_len;
Packit 597cd4
Packit 597cd4
	memset(&buf, 0x00, sizeof(buf));
Packit 597cd4
	iov.iov_base = buf;
Packit 597cd4
	iov.iov_len = sizeof(buf) - 1;
Packit 597cd4
Packit 597cd4
	memset(&smsg, 0x00, sizeof(struct msghdr));
Packit 597cd4
	smsg.msg_name = &from;
Packit 597cd4
	smsg.msg_namelen = fromlen;
Packit 597cd4
	smsg.msg_iov = &iov;
Packit 597cd4
	smsg.msg_iovlen = 1;
Packit 597cd4
	smsg.msg_control = cred_msg;
Packit 597cd4
	smsg.msg_controllen = sizeof(cred_msg);
Packit 597cd4
Packit 597cd4
	res = recvmsg(sock, &smsg, 0);
Packit 597cd4
	if (res < 0) {
Packit 597cd4
		perror("recvfrom(ctrl_iface)");
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
	cmsg = CMSG_FIRSTHDR(&smsg);
Packit 597cd4
	fromlen = smsg.msg_namelen;
Packit 597cd4
	cred = (struct ucred *)CMSG_DATA(cmsg);
Packit 597cd4
Packit 597cd4
	if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
Packit 597cd4
		LLDPAD_INFO("%s: No sender credentials, ignoring\n",
Packit 597cd4
			   __FUNCTION__);
Packit 597cd4
		sprintf(buf,"R%02x", cmd_bad_params);
Packit 597cd4
		sendto(sock, buf, 3, 0, (struct sockaddr *) &from, fromlen);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
	if (cred->uid != 0) {
Packit 597cd4
		LLDPAD_INFO("%s: sender uid=%i, ignoring\n",
Packit 597cd4
			   __FUNCTION__, cred->uid);
Packit 597cd4
		sprintf(buf,"R%02x", cmd_no_access);
Packit 597cd4
		sendto(sock, buf, 3, 0, (struct sockaddr *) &from,
Packit 597cd4
			fromlen);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	buf[res] = '\0';
Packit 597cd4
	/* wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); */
Packit 597cd4
Packit 597cd4
	reply = malloc(reply_size);
Packit 597cd4
	if (reply == NULL) {
Packit 597cd4
		sendto(sock, "R01", 3, 0, (struct sockaddr *) &from,
Packit 597cd4
		       fromlen);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(reply, 0, reply_size);
Packit 597cd4
	process_clif_cmd(clifd, &from, fromlen, buf, res,
Packit 597cd4
			 reply, reply_size, &reply_len);
Packit 597cd4
Packit 597cd4
	/* wpa_hexdump_ascii(MSG_DEBUG, "TX ctrl_iface", (u8 *) reply, reply_len); */
Packit 597cd4
	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
Packit 597cd4
	free(reply);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int ctrl_iface_register(struct clif_data *clifd)
Packit 597cd4
{
Packit 597cd4
	return eloop_register_read_sock(clifd->ctrl_sock, ctrl_iface_receive,
Packit 597cd4
					clifd, NULL);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int ctrl_iface_systemd_socket()
Packit 597cd4
{
Packit 597cd4
	char *env, *ptr;
Packit 597cd4
	unsigned int p, l;
Packit 597cd4
Packit 597cd4
	env = getenv("LISTEN_PID");
Packit 597cd4
	if (!env)
Packit 597cd4
		return -1;
Packit 597cd4
Packit 597cd4
	p = strtoul(env, &ptr, 10);
Packit 597cd4
	if (ptr && ptr == env) {
Packit 597cd4
		LLDPAD_DBG("Invalid value '%s' for LISTEN_PID\n", env);
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
	if ((pid_t)p != getpid()) {
Packit 597cd4
		LLDPAD_DBG("Invalid PID '%d' from LISTEN_PID\n", p);
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
	env = getenv("LISTEN_FDS");
Packit 597cd4
	if (!env) {
Packit 597cd4
		LLDPAD_DBG("LISTEN_FDS is not set\n");
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
	l = strtoul(env, &ptr, 10);
Packit 597cd4
	if (ptr && ptr == env) {
Packit 597cd4
		LLDPAD_INFO("Invalid value '%s' for LISTEN_FDS\n", env);
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
	if (l != 1) {
Packit 597cd4
		LLDPAD_INFO("LISTEN_FDS specified %d fds\n", l);
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
	/* systemd returns fds with an offset of '3' */
Packit 597cd4
	return 3;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int ctrl_iface_init(struct clif_data *clifd)
Packit 597cd4
{
Packit 597cd4
	struct sockaddr_un addr;
Packit 597cd4
	int s = -1;
Packit 597cd4
	socklen_t addrlen;
Packit 597cd4
	const int feature_on = 1;
Packit 597cd4
Packit 597cd4
	clifd->ctrl_sock = -1;
Packit 597cd4
	clifd->ctrl_dst = NULL;
Packit 597cd4
Packit 597cd4
	s = ctrl_iface_systemd_socket();
Packit 597cd4
	if (s != -1) {
Packit 597cd4
		LLDPAD_INFO("using fd %d from systemd\n", s);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
Packit 597cd4
	if (s < 0) {
Packit 597cd4
		LLDPAD_WARN("failed to create CLI socket: %m\n");
Packit 597cd4
		goto fail;
Packit 597cd4
	}
Packit 597cd4
	/* enable receiving of the sender credentials */
Packit 597cd4
	setsockopt(s, SOL_SOCKET, SO_PASSCRED,
Packit 597cd4
		   &feature_on, sizeof(feature_on));
Packit 597cd4
Packit 597cd4
	memset(&addr, 0, sizeof(addr));
Packit 597cd4
	addr.sun_family = AF_LOCAL;
Packit 597cd4
	snprintf(&addr.sun_path[1], sizeof(addr.sun_path) - 1,
Packit 597cd4
		 "%s", LLDP_CLIF_SOCK);
Packit 597cd4
	addrlen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1;
Packit 597cd4
	if (bind(s, (struct sockaddr *) &addr, addrlen) < 0) {
Packit 597cd4
		if (errno == EADDRINUSE)
Packit 597cd4
			LLDPAD_WARN("another lldpad instance is running\n");
Packit 597cd4
		else
Packit 597cd4
			LLDPAD_WARN("failed to bind CLI socket address: %m");
Packit 597cd4
		goto fail;
Packit 597cd4
	}
Packit 597cd4
	/* enable receiving of the sender credentials */
Packit 597cd4
	setsockopt(s, SOL_SOCKET, SO_PASSCRED,
Packit 597cd4
		   &feature_on, sizeof(feature_on));
Packit 597cd4
Packit 597cd4
	LLDPAD_INFO("bound ctrl iface to %s\n", &addr.sun_path[1]);
Packit 597cd4
out:
Packit 597cd4
	clifd->ctrl_sock = s;
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
Packit 597cd4
fail:
Packit 597cd4
	if (s >= 0)
Packit 597cd4
		close(s);
Packit 597cd4
	return -1;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
Packit 597cd4
void ctrl_iface_deinit(struct clif_data *clifd)
Packit 597cd4
{
Packit 597cd4
	struct ctrl_dst *dst, *prev;
Packit 597cd4
Packit 597cd4
	if (clifd->ctrl_sock > -1) {
Packit 597cd4
		eloop_unregister_read_sock(clifd->ctrl_sock);
Packit 597cd4
		close(clifd->ctrl_sock);
Packit 597cd4
		clifd->ctrl_sock = -1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	dst = clifd->ctrl_dst;
Packit 597cd4
	while (dst) {
Packit 597cd4
		prev = dst;
Packit 597cd4
		dst = dst->next;
Packit 597cd4
		free(prev);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	free(clifd);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int is_ctrl_listening(struct ctrl_dst *dst, u32 type)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
	u32 term = ~0;
Packit 597cd4
	u32 all = 0;
Packit 597cd4
	u32 dcbx = LLDP_MOD_DCBX;
Packit 597cd4
Packit 597cd4
	if (!dst)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	for (i=0; dst->tlv_types[i] != term; i++) {
Packit 597cd4
		if ((!type && dst->tlv_types[i] == dcbx) ||
Packit 597cd4
		    dst->tlv_types[i] == type || dst->tlv_types[i] == all)
Packit 597cd4
			return 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
void ctrl_iface_send(struct clif_data *clifd, int level, u32 moduleid,
Packit 597cd4
			char *buf, size_t len)
Packit 597cd4
{
Packit 597cd4
	struct ctrl_dst *dst, *next;
Packit 597cd4
	struct msghdr msg;
Packit 597cd4
	int idx, send;
Packit 597cd4
	struct iovec io[3];
Packit 597cd4
	char levelstr[10] = "";
Packit 597cd4
	char modulestr[10] = "";
Packit 597cd4
Packit 597cd4
	dst = clifd->ctrl_dst;
Packit 597cd4
	if (clifd->ctrl_sock < 0 || dst == NULL)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	snprintf(levelstr, sizeof(levelstr), "%c%d", EVENT_MSG, level);
Packit 597cd4
	if (moduleid) {
Packit 597cd4
		snprintf(modulestr, sizeof(modulestr), "M%08x",moduleid);
Packit 597cd4
		io[0].iov_base = modulestr;
Packit 597cd4
		io[0].iov_len = strlen(modulestr);
Packit 597cd4
	} else {
Packit 597cd4
		io[0].iov_base = NULL;
Packit 597cd4
		io[0].iov_len = 0;
Packit 597cd4
	}
Packit 597cd4
	io[1].iov_base = levelstr;
Packit 597cd4
	io[1].iov_len = strlen(levelstr);
Packit 597cd4
	io[2].iov_base = buf;
Packit 597cd4
	io[2].iov_len = len;
Packit 597cd4
	memset(&msg, 0, sizeof(msg));
Packit 597cd4
	msg.msg_iov = io;
Packit 597cd4
	msg.msg_iovlen = 3;
Packit 597cd4
Packit 597cd4
	idx = 0;
Packit 597cd4
	while (dst) {
Packit 597cd4
		next = dst->next;
Packit 597cd4
		send = 0;
Packit 597cd4
		/* Does dst receive these event messages? */
Packit 597cd4
		send = is_ctrl_listening(dst, moduleid);
Packit 597cd4
		/* Yes */
Packit 597cd4
		if (send && level >= dst->debug_level) {
Packit 597cd4
			msg.msg_name = &dst->addr;
Packit 597cd4
			msg.msg_namelen = dst->addrlen;
Packit 597cd4
			if (sendmsg(clifd->ctrl_sock, &msg, 0) < 0) {
Packit 597cd4
				fprintf(stderr,
Packit 597cd4
					"CTRL_IFACE monitor[%d][%d] %d:%s: ",
Packit 597cd4
					idx, clifd->ctrl_sock, dst->addrlen,
Packit 597cd4
					dst->addr.sun_path);
Packit 597cd4
				perror("sendmsg");
Packit 597cd4
				dst->errors++;
Packit 597cd4
				if (dst->errors > 10) {
Packit 597cd4
					detach_clif_monitor(
Packit 597cd4
						clifd, &dst->addr,
Packit 597cd4
						dst->addrlen);
Packit 597cd4
				}
Packit 597cd4
			} else {
Packit 597cd4
				dst->errors = 0;
Packit 597cd4
			}
Packit 597cd4
		}
Packit 597cd4
		idx++;
Packit 597cd4
		dst = next;
Packit 597cd4
	}
Packit 597cd4
}