/* 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 #include #include #include #include #include #include #include "wrnad.h" #if !defined(IPWRNAD) && !defined(WRNAD_MIPC_PROC) #include #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>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 */