Files
2026-07-30 11:19:44 +05:30

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 */