/* * Write a packet to a data socket. The packet will be sent * out the corresponding node on the specified hook. * Returns -1 if error and sets errno. */ 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; /* Set up destination hook */ sg->sg_family = AF_NETGRAPH; strlcpy(sg->sg_data, hook, NG_HOOKSIZ); sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); _NgDebugSockaddr(sg); if (_gNgDebugLevel >= 3) _NgDebugBytes(buf, len); } /* Send packet */ 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); } /* Done */ return (0); }
/* * Receive a control message. * * On error, this returns -1 and sets errno. * Otherwise, it returns the length of the received reply. */ int NgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path) { u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; socklen_t sglen = sizeof(sgbuf); int len, errnosv; /* Read reply */ len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen); if (len < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recvfrom"); goto errout; } if (path != NULL) strlcpy(path, sg->sg_data, NG_PATHSIZ); /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("RECEIVED %s:", (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); _NgDebugSockaddr(sg); _NgDebugMsg(rep, sg->sg_data); } /* Done */ return (len); errout: errno = errnosv; return (-1); }
/* * Read a packet from a data socket * Returns -1 if error and sets errno. */ 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; /* Read packet */ rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); if (rtn < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recvfrom"); errno = errnosv; return (-1); } /* Copy hook name */ if (hook != NULL) strlcpy(hook, from->sg_data, NG_HOOKSIZ); /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("READ %s from hook \"%s\" (%d bytes)", rtn ? "PACKET" : "EOF", from->sg_data, rtn); if (_gNgDebugLevel >= 3) _NgDebugBytes(buf, rtn); } /* Done */ return (rtn); }
/* * Create a socket type node and give it the supplied name. * Return data and control sockets corresponding to the node. * Returns -1 if error and sets errno. */ int NgMkSockNode(const char *name, int *csp, int *dsp) { char namebuf[NG_NODESIZ]; int cs = -1; /* control socket */ int ds = -1; /* data socket */ int errnosv; /* Empty name means no name */ if (name && *name == 0) name = NULL; /* Create control socket; this also creates the netgraph node. If we get an EPROTONOSUPPORT then the socket node type is not loaded, so load it and try again. */ if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { if (errno == EPROTONOSUPPORT) { 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: /* Assign the node the desired name, if any */ if (name != NULL) { u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; /* Assign name */ 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; } /* Save node name */ strlcpy(namebuf, name, sizeof(namebuf)); } else if (dsp != NULL) { u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; struct ng_mesg *const resp = (struct ng_mesg *) rbuf; struct nodeinfo *const ni = (struct nodeinfo *) resp->data; /* Find out the node ID */ if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("send nodeinfo"); goto errout; } if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recv nodeinfo"); goto errout; } /* Save node "name" */ snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); } /* Create data socket if desired */ if (dsp != NULL) { u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; /* Create data socket, initially just "floating" */ if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("socket"); goto errout; } /* Associate the data socket with the node */ 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; } } /* Return the socket(s) */ if (csp) *csp = cs; else close(cs); if (dsp) *dsp = ds; return (0); errout: /* Failed */ if (cs >= 0) close(cs); if (ds >= 0) close(ds); errno = errnosv; return (-1); }
/* * Send a message to a node using control socket node "cs". * Returns -1 if error and sets errno appropriately, otherwise zero. */ static int NgDeliverMsg(int cs, const char *path, const struct ng_mesg *hdr, const void *args, size_t arglen) { u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; u_char *buf = NULL; struct ng_mesg *msg; int errnosv = 0; int rtn = 0; /* Sanity check */ if (args == NULL) arglen = 0; /* Get buffer */ if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("malloc"); rtn = -1; goto done; } msg = (struct ng_mesg *) buf; /* Finalize message */ *msg = *hdr; msg->header.arglen = arglen; memcpy(msg->data, args, arglen); /* Prepare socket address */ sg->sg_family = AF_NETGRAPH; /* XXX handle overflow */ strlcpy(sg->sg_data, path, NG_PATHSIZ); sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("SENDING %s:", (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); _NgDebugSockaddr(sg); _NgDebugMsg(msg, sg->sg_data); } /* Send it */ if (sendto(cs, msg, sizeof(*msg) + arglen, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("sendto(%s)", sg->sg_data); rtn = -1; goto done; } /* Wait for reply if there should be one. */ if (msg->header.cmd & NGM_HASREPLY && !(msg->header.flags & NGF_RESP)) { struct pollfd rfds; int n; rfds.fd = cs; rfds.events = POLLIN; rfds.revents = 0; n = poll(&rfds, 1, INFTIM); if (n == -1) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("poll"); rtn = -1; } } done: /* Done */ free(buf); /* OK if buf is NULL */ errno = errnosv; return (rtn); }