|
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 |
}
|