#include <sys/types.h>
#include <sys/socket.h>
#include <stdarg.h>
#include <netgraph/ng_message.h>
#include <netgraph/ng_socket.h>
#include "netgraph.h"
#include "internal.h"
#define NG_SOCKET_KLD "ng_socket.ko"
int
NgMkSockNode(const char *name, int *csp, int *dsp)
{
char namebuf[NG_NODESIZ];
int cs = -1;
int ds = -1;
int errnosv;
if (name && *name == 0)
name = NULL;
if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
if (errno == EAFNOSUPPORT) {
if (kldload(NG_SOCKET_KLD) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("can't load %s", NG_SOCKET_KLD);
goto errout;
}
cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
if (cs >= 0)
goto gotNode;
}
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("socket");
goto errout;
}
gotNode:
if (name != NULL) {
u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
strlcpy(sg->sg_data, name, NG_NODESIZ);
sg->sg_family = AF_NETGRAPH;
sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("bind(%s)", sg->sg_data);
goto errout;
}
strlcpy(namebuf, name, sizeof(namebuf));
} else if (dsp != NULL) {
union {
u_char rbuf[sizeof(struct ng_mesg) +
sizeof(struct nodeinfo)];
struct ng_mesg res;
} res;
struct nodeinfo *const ni = (struct nodeinfo *) res.res.data;
if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
NGM_NODEINFO, NULL, 0) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("send nodeinfo");
goto errout;
}
if (NgRecvMsg(cs, &res.res, sizeof(res.rbuf), NULL) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("recv nodeinfo");
goto errout;
}
snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
}
if (dsp != NULL) {
u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("socket");
goto errout;
}
snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
sg->sg_family = AF_NETGRAPH;
sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("connect(%s)", sg->sg_data);
goto errout;
}
}
if (csp)
*csp = cs;
else
close(cs);
if (dsp)
*dsp = ds;
return (0);
errout:
if (cs >= 0)
close(cs);
if (ds >= 0)
close(ds);
errno = errnosv;
return (-1);
}
int
NgNameNode(int cs, const char *path, const char *fmt, ...)
{
struct ngm_name ngn;
va_list args;
va_start(args, fmt);
vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
va_end(args);
if (NgSendMsg(cs, path,
NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
if (_gNgDebugLevel >= 1)
NGLOGX("%s: failed", __func__);
return (-1);
}
return (0);
}
int
NgRecvData(int ds, u_char * buf, size_t len, char *hook)
{
u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
socklen_t fromlen = sizeof(frombuf);
int rtn, errnosv;
rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
if (rtn < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("recvfrom");
errno = errnosv;
return (-1);
}
if (hook != NULL)
strlcpy(hook, from->sg_data, NG_HOOKSIZ);
if (_gNgDebugLevel >= 2) {
NGLOGX("READ %s from hook \"%s\" (%d bytes)",
rtn ? "PACKET" : "EOF", from->sg_data, rtn);
if (_gNgDebugLevel >= 3)
_NgDebugBytes(buf, rtn);
}
return (rtn);
}
int
NgAllocRecvData(int ds, u_char **buf, char *hook)
{
int len;
socklen_t optlen;
optlen = sizeof(len);
if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
(*buf = malloc(len)) == NULL)
return (-1);
if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
free(*buf);
return (len);
}
int
NgSendData(int ds, const char *hook, const u_char * buf, size_t len)
{
u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
int errnosv;
sg->sg_family = AF_NETGRAPH;
strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
if (_gNgDebugLevel >= 2) {
NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
_NgDebugSockaddr(sg);
if (_gNgDebugLevel >= 3)
_NgDebugBytes(buf, len);
}
if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
errnosv = errno;
if (_gNgDebugLevel >= 1)
NGLOG("sendto(%s)", sg->sg_data);
errno = errnosv;
return (-1);
}
return (0);
}