337 lines
8.6 KiB
C
337 lines
8.6 KiB
C
/* wrnad_mipc.c - Wind River network acceleration daemon (NAD) */
|
|
|
|
/*
|
|
* Copyright (c) 2010 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute or otherwise make use of this software
|
|
* may be licensed only pursuant to the terms of an applicable Wind River
|
|
* license agreement.
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <syslog.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "wrnad.h"
|
|
|
|
#if !defined(IPWRNAD) && !defined(WRNAD_MIPC_PROC)
|
|
#include <linux/mipc.h>
|
|
#endif
|
|
|
|
/* defines */
|
|
|
|
#ifdef IPWRNAD
|
|
|
|
#define MIPC_AF 0 /* Shared Memory */
|
|
|
|
#define MIPC_SOCK_STREAM 1
|
|
#define MIPC_SOCK_DGRAM 2
|
|
#define MIPC_SOCK_RDM 4
|
|
#define MIPC_SOCK_SEQPACKET 5
|
|
|
|
#endif
|
|
|
|
/* typedefs */
|
|
|
|
#ifdef IPWRNAD
|
|
|
|
typedef void *MIPC_ZBUFFER;
|
|
|
|
struct mipc_sockaddr
|
|
{
|
|
unsigned short family; /* family number (MIPC_AF) */
|
|
unsigned short busNum; /* bus number */
|
|
unsigned short nodeNum; /* node number */
|
|
unsigned short portNum; /* port number */
|
|
};
|
|
|
|
#endif
|
|
|
|
/* imports */
|
|
|
|
#ifdef IPWRNAD
|
|
|
|
extern int mipc_send(int fd, const void * buf, size_t buflen, int flags);
|
|
extern int mipc_socket(int family, int type, int protocol);
|
|
extern int mipc_bind(int fd, struct mipc_sockaddr *myaddr, size_t addrlen);
|
|
extern int mipc_close(int fd);
|
|
extern int mipc_connect(int fd, struct mipc_sockaddr *servaddr, size_t addrlen);
|
|
extern int mipc_getsockname(int fd, struct mipc_sockaddr *addr, size_t *addrlen);
|
|
|
|
#endif
|
|
|
|
/* globals */
|
|
|
|
/* locals */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_mipc_close - close mipc socket
|
|
*
|
|
* This routine closes a mipc socket
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void
|
|
wrnad_mipc_close(int fd)
|
|
{
|
|
#if defined(IPWRNAD)
|
|
if (fd >= 0)
|
|
mipc_close(fd);
|
|
#else
|
|
if (fd >= 0)
|
|
close(fd);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_mipc_open - open and connect mipc socket
|
|
*
|
|
* This routine opens a rtnetlink socket and binds it.
|
|
*
|
|
* RETURNS: socket descriptor if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
int
|
|
wrnad_mipc_open(int bus, int node, int port)
|
|
{
|
|
int fd;
|
|
#if defined(IPWRNAD)
|
|
int rc;
|
|
size_t addrlen;
|
|
struct mipc_sockaddr addr;
|
|
|
|
fd = mipc_socket(MIPC_AF, MIPC_SOCK_SEQPACKET, 0);
|
|
if (fd < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Could not create a MIPC socket.\n");
|
|
return -1;
|
|
}
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d created.", fd);
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
if ((rc = mipc_bind(fd, &addr, sizeof(struct mipc_sockaddr))) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to bind mipc socket %d (err=%d).\n", fd, rc);
|
|
mipc_close(fd);
|
|
return -1;
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addrlen = sizeof(struct mipc_sockaddr);
|
|
if ((rc = mipc_getsockname(fd, &addr, &addrlen)) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed getsockname() on mipc socket %d (err=%d).\n", fd, rc);
|
|
mipc_close(fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d bound to node %d on port %d.",
|
|
fd, addr.nodeNum, addr.portNum);
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.busNum = (unsigned short)bus;
|
|
addr.nodeNum = (unsigned short)node;
|
|
addr.portNum = (unsigned short)port;
|
|
if ((rc = mipc_connect(fd, &addr, sizeof(struct mipc_sockaddr))) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to connect mipc socket (%d) (err=%d).\n", fd, rc);
|
|
mipc_close(fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d connected to node %d on port %d.", fd, node, port);
|
|
|
|
#elif !defined(WRNAD_MIPC_PROC)
|
|
int rc;
|
|
size_t addrlen;
|
|
struct sockaddr_mipc addr;
|
|
int txbufs;
|
|
|
|
fd = socket(AF_MIPC, SOCK_SEQPACKET, 0);
|
|
if (fd < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to open mipc socket!");
|
|
return -1;
|
|
}
|
|
|
|
txbufs = 16;
|
|
rc = setsockopt(fd, SOL_MIPC, MIPC_SO_TXBUFS, &txbufs, sizeof(txbufs));
|
|
if (rc != 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to set MIPC_SO_TXBUFS: ret=%d, errno=%d\n",
|
|
rc, errno);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.family = AF_MIPC;
|
|
addr.busNum = (unsigned short)bus;
|
|
addr.nodeNum = (unsigned short)MIPC_NODE_ANY;
|
|
addr.portNum = (unsigned short)MIPC_PORT_ANY;
|
|
|
|
if ((rc = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_mipc))) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to bind mipc socket %d (err=%d) %d.\n", fd, rc, errno);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
addrlen = sizeof(struct sockaddr_mipc);
|
|
if ((rc = getsockname(fd, (struct sockaddr *)&addr, &addrlen)) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed getsockname() on mipc socket %d (err=%d).\n", fd, rc);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d bound to node %d on port %d.",
|
|
fd, addr.nodeNum, addr.portNum);
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.family = AF_MIPC;
|
|
addr.busNum = (unsigned short)bus;
|
|
addr.nodeNum = (unsigned short)node;
|
|
addr.portNum = (unsigned short)port;
|
|
if ((rc = connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_mipc))) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to connect mipc socket (%d) (err=%d) %d.\n", fd, rc, errno);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d open.", fd);
|
|
#else
|
|
fd = open(WRNAD_PROC_FILE, O_RDWR, 0);
|
|
if (fd < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to open mipc socket!");
|
|
return -1;
|
|
}
|
|
wrnad_log(LOG_DEBUG, "Mipc socket %d open.", fd);
|
|
#endif /* !IPWRNAD */
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_mipc_send_netlink - send netlink message on mipc socket
|
|
*
|
|
* This routine sends a netlink message over a mipc socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
/* If this flag is set in the NLMSG flag field, the VxWorks (c)NAEs will
|
|
* interpret it as a linux formed NETLINK command.
|
|
* That is, proper conversion will be done on AF_INET6, interface flags,
|
|
* routing types etc.
|
|
*/
|
|
#define IP_NLM_F_LINUX 0x4000
|
|
|
|
int
|
|
wrnad_mipc_send_netlink(int fd, struct nlmsghdr *nlh)
|
|
{
|
|
int ret, len;
|
|
#if defined(IPWRNAD)
|
|
/* Forcibly clear it - IPWRNAD is never set in a LINUX compile */
|
|
nlh->nlmsg_flags &= ~IP_NLM_F_LINUX;
|
|
len = NLMSG_ALIGN(nlh->nlmsg_len);
|
|
ret = mipc_send(fd, nlh, len, 0);
|
|
#elif !defined(WRNAD_MIPC_PROC)
|
|
/* Forcibly add it - Linux Style MGMT OS */
|
|
nlh->nlmsg_flags |= IP_NLM_F_LINUX;
|
|
len = NLMSG_ALIGN(nlh->nlmsg_len);
|
|
ret = send(fd, nlh, len, 0);
|
|
#else
|
|
/* Forcibly add it - Linux Style MGMT OS */
|
|
nlh->nlmsg_flags |= IP_NLM_F_LINUX;
|
|
len = NLMSG_ALIGN(nlh->nlmsg_len);
|
|
ret = write(fd, nlh, len);
|
|
#endif /* !IPWRNAD */
|
|
if (ret < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to send %d bytes of rtnetlink message on mipc socket %d! error=%d", len, fd, ret);
|
|
return -1;
|
|
}
|
|
else if (ret != len)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Only %d of %d bytes of rtnetlink message was sent on mipc socket %d!", ret, len, fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_INFO, "Rtnetlink message type %s with length %d sent on mipc socket %d.",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), len, fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_mipc_send_pfkey - send pfkey message on mipc socket
|
|
*
|
|
* This routine sends a pfkey message over a mipc socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
int
|
|
wrnad_mipc_send_pfkey(int fd, struct sadb_msg *msg)
|
|
{
|
|
int ret, len;
|
|
|
|
#ifdef IPWRNAD
|
|
len = msg->sadb_msg_len << 3;
|
|
ret = mipc_send(fd, msg, len, 0);
|
|
#else
|
|
int i;
|
|
char buf[1024];
|
|
unsigned char *p;
|
|
|
|
len = msg->sadb_msg_len << 3;
|
|
p = (unsigned char *)msg;
|
|
for (i=0; i<len && i<((sizeof(buf)>>1)-1); i++)
|
|
sprintf(&buf[i<<1], "%02x", p[i]);
|
|
buf[i<<1] = '\0';
|
|
wrnad_log(LOG_DEBUG, "PFKEY message: %s", buf);
|
|
ret = write(fd, msg, len);
|
|
#endif /* IPWRNAD */
|
|
|
|
if (ret < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to send %d bytes of pfkey message on mipc socket %d! error=%d", len, fd, ret);
|
|
return -1;
|
|
}
|
|
else if (ret != len)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Only %d of %d bytes of pfkey message was sent on mipc socket %d!", ret, len, fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_INFO, "Pfkey message type %s with length %d sent on mipc socket %d.",
|
|
wrnad_pfkey_typestr(msg->sadb_msg_type), len, fd);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|