PERFORCE change 124747 for review
Fredrik Lindberg
fli at FreeBSD.org
Sun Aug 5 11:59:30 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=124747
Change 124747 by fli at fli_nexus on 2007/08/05 18:58:30
- Add support to manipulate the record database. Allows add,
remove and list operations (root only).
- Add support to view and flush the cache (root only).
- Add support to view active interfaces (root only).
- Follow name change (mdnsd_clipkg.h -> mdnsd_ipc.h).
- Save client credentials aquired from socket.
- Change how messages are read. Read for as long as data
is available, also use length information encoded in message
to properly separate messages.
Affected files ...
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.h#2 edit
Differences ...
==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 (text+ko) ====
@@ -34,13 +34,14 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "event.h"
#include "clisrv.h"
#include "mdnsd.h"
-#include "mdnsd_clipkg.h"
+#include "mdnsd_ipc.h"
#include "log.h"
#include "objalloc.h"
#include "utf8.h"
@@ -52,13 +53,44 @@
static int evh_cli(const struct event_io *, const ev_arg);
static int cp_parse(struct cs_client *, char *, size_t, int);
-static int mtpf_query(struct cs_client *, struct cp_head *, char *, size_t);
+static int mtpf_query(struct cs_client *, struct mipc_head *, char *, size_t);
+static int mtpf_if_list(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_ident_list(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_ident_add(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_ident_del(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_name_add(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_name_del(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_name_list(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_res_add(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_res_del(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_res_list(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_cache_flush(struct cs_client *, struct mipc_head *, char *,
+ size_t);
+static int mtpf_cache_list(struct cs_client *, struct mipc_head *, char *f,
+ size_t);
static void send_error(struct cs_client *, int, int);
static void send_ack(struct cs_client *, int);
-static int queryadd(struct cs_client *, struct csc_query *, int, int, int);
-static int querydel(struct cs_client *, struct csc_query * , int);
+static int queryadd(struct cs_client *, struct csc_query *, unsigned int,
+ int, int);
+static int querydel(struct cs_client *, struct csc_query * , unsigned int);
+
+#define IPC_SETHDR(mih, id, type, len) \
+ (mih)->mih_ver = MIPC_VERSION; \
+ (mih)->mih_id = id; \
+ (mih)->mih_msgtype = type; \
+ (mih)->mih_msglen = len;
/*
* Open UNIX pipe socket to clients
@@ -205,11 +237,12 @@
TAILQ_INSERT_TAIL(&cs->cs_head, csc, csc_next);
csc->csc_sock = sock;
csc->csc_serv = cs;
+ csc->csc_suser = 0;
eva.ptr = csc;
csc->csc_evid = event_add(g->g_evl, EVENT_TYPE_IO, evh_cli, &eva,
evh_clisetup_init, &eva);
- dprintf(DEBUG_CS, "New UNIX pipe client csc=%x", csc);
+ dprintf(DEBUG_CS, "New UNIX pipe client csc=%x, sock=%d", csc, sock);
out:
MTX_UNLOCK(cs, cs_mtx);
return (0);
@@ -270,11 +303,12 @@
struct cs_client *csc;
struct cmsghdr *cmptr;
struct sockcred *cred;
- int n, sock, suser, error;
+ struct mipc_head *mih;
+ int n, sock, error, len;
struct msghdr msg;
struct iovec iov[1];
- char control[CMSG_LEN(SOCKCREDSIZE(1))];
- char buf[CP_MAXPLEN];
+ char control[CMSG_LEN(SOCKCREDSIZE(1)) + sizeof(struct cmsghdr)];
+ char buf[MIPC_MAXPLEN];
csc = arg.ptr;
MDNS_INIT_ASSERT(csc, csc_magic);
@@ -282,8 +316,6 @@
sock = csc->csc_sock;
- iov[0].iov_base = buf;
- iov[0].iov_len = CP_MAXPLEN;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
@@ -291,30 +323,43 @@
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
msg.msg_flags = 0;
+ iov[0].iov_base = buf + sizeof(struct mipc_head);
+
+ for (;;) {
+ n = read(sock, buf, sizeof(struct mipc_head));
+ if (n < (signed int)sizeof(struct mipc_head))
+ break;
- n = recvmsg(sock, &msg, 0);
- if (n < 0)
- goto out;
- cmptr = CMSG_FIRSTHDR(&msg);
- suser = 0;
- if (cmptr != NULL) {
- if (cmptr->cmsg_type == SCM_CREDS &&
- cmptr->cmsg_level == SOL_SOCKET) {
- cred = (struct sockcred *)CMSG_DATA(cmptr);
- if (cred->sc_euid == 0)
- suser = 1;
+ mih = (struct mipc_head *)buf;
+ if (mih->mih_ver != MIPC_VERSION)
+ continue;
+
+ len = mih->mih_msglen > MIPC_MAXPLEN ?
+ MIPC_MAXPLEN : mih->mih_msglen;
+ iov[0].iov_len = len - sizeof(struct mipc_head);
+
+ n = recvmsg(sock, &msg, 0);
+ if ((unsigned int)n != iov[0].iov_len)
+ continue;
+
+ /* Check credentials */
+ cmptr = CMSG_FIRSTHDR(&msg);
+ if (cmptr != NULL) {
+ if (cmptr->cmsg_type == SCM_CREDS &&
+ cmptr->cmsg_level == SOL_SOCKET) {
+ cred = (struct sockcred *)CMSG_DATA(cmptr);
+ csc->csc_suser = (cred->sc_euid == 0) ? 1 : 0;
+ }
}
- }
- dprintf(DEBUG_CS, "Received packet on UNIX pipe "
- "csc=%x, len=%d, suser=%d", csc, n, suser);
+ dprintf(DEBUG_CS, "Received packet on UNIX pipe csc=%x, "
+ "len=%d, suser=%d, sock=%d", csc, n, csc->csc_suser, sock);
- error = cp_parse(csc, buf, n, suser);
- if (error != 0) {
- dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc);
- }
+ error = cp_parse(csc, buf, n, csc->csc_suser);
+ if (error != 0)
+ dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc);
+ }
-out:
MTX_UNLOCK(csc, csc_mtx);
return (0);
}
@@ -322,7 +367,7 @@
/*
* Parser defintions to individual message types.
*/
-typedef int (*mtp_func) (struct cs_client *, struct cp_head *, char *, size_t);
+typedef int (*mtp_func) (struct cs_client *, struct mipc_head *, char *, size_t);
struct msgtype_parser {
int mtp_msgtype; /* message type */
int mtp_suser; /* super user privs required */
@@ -333,163 +378,1119 @@
* Table of recognized message types and their corresponding parser.
*/
static struct msgtype_parser mtp_table[] = {
- { .mtp_msgtype = CPM_ACK, .mtp_suser = 0, .mtp_parser = NULL },
- { .mtp_msgtype = CPM_ERROR, .mtp_suser = 0, .mtp_parser = NULL },
- { .mtp_msgtype = CPM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query }
+ { .mtp_msgtype = MIM_ACK, .mtp_suser = 0, .mtp_parser = NULL },
+ { .mtp_msgtype = MIM_ERROR, .mtp_suser = 0, .mtp_parser = NULL },
+ { .mtp_msgtype = MIM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query },
+ { .mtp_msgtype = MIM_IF_LIST, .mtp_suser = 1,
+ .mtp_parser = mtpf_if_list },
+ { .mtp_msgtype = MIM_IDENT_LIST, .mtp_suser = 1,
+ .mtp_parser = mtpf_ident_list },
+ { .mtp_msgtype = MIM_IDENT_ADD, .mtp_suser = 1,
+ .mtp_parser = mtpf_ident_add },
+ { .mtp_msgtype = MIM_IDENT_DEL, .mtp_suser = 1,
+ .mtp_parser = mtpf_ident_del },
+ { .mtp_msgtype = MIM_IDENT_NAME_ADD, .mtp_suser = 1,
+ .mtp_parser = mtpf_name_add },
+ { .mtp_msgtype = MIM_IDENT_NAME_DEL, .mtp_suser = 1,
+ .mtp_parser = mtpf_name_del },
+ { .mtp_msgtype = MIM_IDENT_NAME_LIST, .mtp_suser = 1,
+ .mtp_parser = mtpf_name_list },
+ { .mtp_msgtype = MIM_IDENT_RES_ADD, .mtp_suser = 1,
+ .mtp_parser = mtpf_res_add },
+ { .mtp_msgtype = MIM_IDENT_RES_DEL, .mtp_suser = 1,
+ .mtp_parser = mtpf_res_del },
+ { .mtp_msgtype = MIM_IDENT_RES_LIST, .mtp_suser = 1,
+ .mtp_parser = mtpf_res_list },
+ { .mtp_msgtype = MIM_CACHE_FLUSH, .mtp_suser = 1,
+ .mtp_parser = mtpf_cache_flush },
+ { .mtp_msgtype = MIM_CACHE_LIST, .mtp_suser = 1,
+ .mtp_parser = mtpf_cache_list }
};
static int mtp_table_size = sizeof(mtp_table) / sizeof(struct msgtype_parser);
-
/*
* Parse packet received on UNIX pipe
*/
static int
cp_parse(struct cs_client *csc, char *buf, size_t len, int suser)
{
- struct cp_head *cph;
+ struct mipc_head *mih;
int i, error = 0;
- if (len < sizeof(struct cp_head))
- return (CPE_IVAL);
+
+ if (len < sizeof(struct mipc_head))
+ return (-1);
- cph = (struct cp_head *)buf;
- if (cph->cph_ver != CP_VERSION)
- return (CPE_IVAL);
+ mih = (struct mipc_head *)buf;
+
+ dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d",
+ mih->mih_ver, mih->mih_msgtype);
+
+ if (mih->mih_ver != MIPC_VERSION) {
+ error = MIE_IVAL;
+ goto error;
+ }
for (i = 0; i < mtp_table_size; i++)
- if (cph->cph_msgtype == mtp_table[i].mtp_msgtype)
+ if (mih->mih_msgtype == mtp_table[i].mtp_msgtype)
break;
- if (i == mtp_table_size)
- return (CPE_IVAL);
+ if (i == mtp_table_size) {
+ error = MIE_IVAL;
+ goto error;
+ }
- if (mtp_table[i].mtp_suser && !suser)
- return (CPE_PERM);
-
- dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d",
- cph->cph_ver, cph->cph_msgtype);
+ if (mtp_table[i].mtp_suser && !suser) {
+ dprintf(DEBUG_CS, "Privileged request from non-root user "
+ "csc=%x", csc);
+ error = MIE_PERM;
+ goto error;
+ }
if (mtp_table[i].mtp_parser != NULL) {
- error = mtp_table[i].mtp_parser(csc, cph,
- buf + sizeof(struct cp_head),
- len - sizeof(struct cp_head));
+ error = mtp_table[i].mtp_parser(csc, mih,
+ buf + sizeof(struct mipc_head),
+ len - sizeof(struct mipc_head));
}
if (error != 0)
- send_error(csc, cph->cph_id, error);
+ goto error;
- return (error);
+ return (0);
+error:
+ send_error(csc, mih->mih_id, error);
+ return (-1);
}
/*
* Query parser
*/
static int
-mtpf_query(struct cs_client *csc, struct cp_head *cph, char *buf, size_t len)
+mtpf_query(struct cs_client *csc, struct mipc_head *mih, char *buf, size_t len)
{
- struct cp_query *cpq;
+ struct mipc_query *miq;
wchar_t *wp;
int error, retval = 0;
struct csc_query cscq;
wchar_t name[MDNS_RECORD_LEN+1];
- if (len < sizeof(struct cp_query))
- return (CPE_IVAL);
+ if (len < sizeof(struct mipc_query))
+ return (MIE_IVAL);
- cpq = (struct cp_query *)buf;
- if ((cpq->cpq_len * sizeof(wchar_t)) + sizeof(struct cp_query) != len)
- return (CPE_IVAL);
+ miq = (struct mipc_query *)buf;
+ if ((miq->miq_len * sizeof(wchar_t)) + sizeof(struct mipc_query) != len)
+ return (MIE_IVAL);
- wp = (wchar_t *)(buf + sizeof(struct cp_query));
- memcpy(name, wp, cpq->cpq_len * sizeof(wchar_t));
- name[cpq->cpq_len] = L'\0';
+ wp = (wchar_t *)(buf + sizeof(struct mipc_query));
+ memcpy(name, wp, miq->miq_len * sizeof(wchar_t));
+ name[miq->miq_len] = L'\0';
error = utf8_encode(name, cscq.cscq_qs.name, MDNS_RECORD_LEN);
if (error < 0)
- return (CPE_IVAL);
+ return (MIE_IVAL);
dprintf(DEBUG_CS,"Query message class=%d, type=%d, name=%ls, "
- "cmd=%d, fam=%d, ifidx=%d, timeout=%d", cpq->cpq_class,
- cpq->cpq_type, name, cpq->cpq_cmd, cpq->cpq_fam,
- cpq->cpq_ifidx, cpq->cpq_timeout);
+ "cmd=%d, fam=%d, ifidx=%d, timeout=%d", miq->miq_class,
+ miq->miq_type, name, miq->miq_cmd, miq->miq_fam,
+ miq->miq_ifidx, miq->miq_timeout);
cscq.cscq_qs.q_name = cscq.cscq_qs.name;
- cscq.cscq_qs.q_type = cpq->cpq_type;
- cscq.cscq_qs.q_class = cpq->cpq_class;
- cscq.cscq_id = cph->cph_id;
+ cscq.cscq_qs.q_type = miq->miq_type;
+ cscq.cscq_qs.q_class = miq->miq_class;
+ cscq.cscq_id = mih->mih_id;
cscq.cscq_resp = 0;
cscq.cscq_csc = csc;
MDNS_INIT_SET(&cscq, cscq_magic);
- switch (cpq->cpq_cmd) {
- case CPQ_CMD_ONESHOT:
- error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam,
- cpq->cpq_timeout);
+ switch (miq->miq_cmd) {
+ case MIQ_CMD_ONESHOT:
+ error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam,
+ miq->miq_timeout);
if (error != 0)
- retval = CPE_IVAL;
+ retval = MIE_IVAL;
break;
- case CPQ_CMD_CREG:
- error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam, 0);
+ case MIQ_CMD_CREG:
+ error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam, 0);
if (error == 0)
- send_ack(csc, cph->cph_id);
+ send_ack(csc, mih->mih_id);
else
- retval = CPE_REGQ;
+ retval = MIE_REGQ;
break;
- case CPQ_CMD_CDEREG:
- error = querydel(csc, &cscq, cpq->cpq_ifidx);
+ case MIQ_CMD_CDEREG:
+ error = querydel(csc, &cscq, miq->miq_ifidx);
if (error == 0)
- send_ack(csc, cph->cph_id);
+ send_ack(csc, mih->mih_id);
else
- retval = CPE_DEREGQ;
+ retval = MIE_DEREGQ;
break;
default:
- return (CPE_IVAL);
+ return (MIE_IVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * List active interfaces
+ */
+static int
+mtpf_if_list(struct cs_client *csc, struct mipc_head *mih, char *buf __unused,
+ size_t len)
+{
+ struct md_glob *g;
+ struct md_if *mif;
+ size_t iflen;
+ struct mipc_if miif;
+ struct mipc_head rmih;
+ struct iovec iov[3];
+
+ if (len != 0)
+ return (MIE_IVAL);
+
+ dprintf(DEBUG_CS, "Interface list request csc=%x", csc);
+
+ g = csc->csc_serv->cs_glob;
+ IPC_SETHDR(&rmih, mih->mih_id, MIM_IF, 0);
+ iov[0].iov_base = &rmih;
+ iov[0].iov_len = sizeof(struct mipc_head);
+ iov[1].iov_base = &miif;
+ iov[1].iov_len = sizeof(struct mipc_if);
+
+ RW_RLOCK(g, g_lock);
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ iflen = strlen(mif->mif_ifnam);
+ iov[2].iov_base = mif->mif_ifnam;
+ iov[2].iov_len = iflen;
+ miif.miif_ifidx = mif->mif_index;
+ miif.miif_len = iflen;
+ miif.miif_flags = 0;
+ rmih.mih_msglen =
+ sizeof(struct mipc_head) + sizeof(struct mipc_if) + iflen;
+ writev(csc->csc_sock, iov, 3);
+ }
+
+ RW_UNLOCK(g, g_lock);
+ send_ack(csc, mih->mih_id);
+ return (0);
+}
+
+/*
+ * List database record idents
+ */
+static int
+mtpf_ident_list(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct mipc_dbi_list *miil;
+ struct md_glob *g;
+ struct md_if *mif;
+ char **ident;
+ int i, ilen;
+ struct mipc_dbident mii;
+ struct mipc_head rmih;
+ struct iovec iov[3];
+
+ if (len < sizeof(struct mipc_dbi_list))
+ return (MIE_IVAL);
+
+ miil = (struct mipc_dbi_list *)buf;
+ g = csc->csc_serv->cs_glob;
+
+ if (miil->miil_ifidx > g->g_ifs_max)
+ return (MIE_IVAL);
+
+ mif = g->g_ifs[miil->miil_ifidx];
+ if (mif == NULL)
+ return (MIE_IVAL);
+
+ IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT, 0);
+ iov[0].iov_base = &rmih;
+ iov[0].iov_len = sizeof(struct mipc_head);
+ iov[1].iov_base = &mii;
+ iov[1].iov_len = sizeof(struct mipc_dbident);
+ mii.mii_ifidx = mif->mif_index;
+
+ ident = dbr_ident_list(&mif->mif_dbr);
+
+ i = 0;
+ while (ident[i] != NULL) {
+ ilen = strlen(ident[i]);
+ rmih.mih_msglen = sizeof(struct mipc_head) +
+ sizeof(struct mipc_dbident) + ilen;
+ mii.mii_len = ilen;
+ iov[2].iov_base = ident[i];
+ iov[2].iov_len = ilen;
+ writev(csc->csc_sock, iov, 3);
+ i++;
+ }
+
+ dprintf(DEBUG_CS, "Sent identifier list to client, csc=%x", csc);
+
+ send_ack(csc, mih->mih_id);
+ dbr_ident_list_free(ident);
+ return (0);
+}
+
+/*
+ * IPC MIM_IDENT_ADD - Add an itentifier to the record database
+ * The message type MIM_IDENT_ADD allows a privileged client to add
+ * a new resource identifier to the record database, either to a specific
+ * interface index or to all active interfaces.
+ */
+static int
+mtpf_ident_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct mipc_dbident *mii;
+ struct md_glob *g;
+ struct md_if *mif;
+ char *ident, *p;
+ int error = 0;
+
+ g = csc->csc_serv->cs_glob;
+
+ if (len < sizeof(struct mipc_dbident))
+ return (MIE_IVAL);
+
+ mii = (struct mipc_dbident *)buf;
+ p = buf + sizeof(struct mipc_dbident);
+ len -= sizeof(struct mipc_dbident);
+
+ if (mii->mii_ifidx > g->g_ifs_max)
+ return (MIE_IVAL);
+
+ if (mii->mii_len > len)
+ return (MIE_IVAL);
+
+ ident = malloc(mii->mii_len + 1);
+ if (ident == NULL)
+ return (MIE_INTE);
+ memcpy(ident, p, mii->mii_len);
+ ident[mii->mii_len] = '\0';
+
+ dprintf(DEBUG_CS, "Request to add resource identifier %s, ifidx=%d "
+ "csc=%x", ident, mii->mii_ifidx, csc);
+
+ RW_RLOCK(g, g_lock);
+
+ /*
+ * Only add the identifier to a specific interface index
+ * if one was specified in the message.
+ */
+ if (mii->mii_ifidx != 0) {
+ mif = g->g_ifs[mii->mii_ifidx];
+ if (mif == NULL) {
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ return (MIE_IVAL);
+ }
+ error = dbr_ident_add(&mif->mif_dbr, ident);
+ }
+ else {
+ /* We ignore errors in this case */
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ dbr_ident_add(&mif->mif_dbr, ident);
+ }
+ }
+
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ if (error < 0)
+ return (MIE_EXISTS);
+
+ send_ack(csc, mih->mih_id);
+ return (0);
+}
+
+/*
+ * IPC MIM_IDENT_DEL - Remove an identifier from the record database
+ */
+static int
+mtpf_ident_del(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct mipc_dbident *mii;
+ struct md_glob *g;
+ struct md_if *mif;
+ char *p, *ident;
+ int error = 0;
+
+ g = csc->csc_serv->cs_glob;
+
+ if (len < sizeof(struct mipc_dbident))
+ return (MIE_IVAL);
+
+ mii = (struct mipc_dbident *)buf;
+ p = buf + sizeof(struct mipc_dbident);
+ len -= sizeof(struct mipc_dbident);
+
+ if (mii->mii_ifidx > g->g_ifs_max)
+ return (MIE_IVAL);
+
+ if (mii->mii_len > len)
+ return (MIE_IVAL);
+
+ ident = malloc(mii->mii_len + 1);
+ if (ident == NULL)
+ return (MIE_INTE);
+ memcpy(ident, p, mii->mii_len);
+ ident[mii->mii_len] = '\0';
+
+ dprintf(DEBUG_CS, "Request to remove identifier %s, ifidx=%d, csc=%x",
+ ident, mii->mii_ifidx, csc);
+
+ RW_RLOCK(g, g_lock);
+
+ if (mii->mii_ifidx != 0) {
+ mif = g->g_ifs[mii->mii_ifidx];
+ if (mif == NULL) {
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ return (MIE_IVAL);
+ }
+ error = dbr_ident_del(&mif->mif_dbr, ident);
+ }
+ else {
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ dbr_ident_del(&mif->mif_dbr, ident);
+ }
+ }
+
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ if (error < 0)
+ return (MIE_EXISTS);
+
+ send_ack(csc, mih->mih_id);
+ return (0);
+}
+
+static int
+parse_dbi_name(char *buf, size_t len, struct mipc_dbi_name **miin, char **ident,
+ wchar_t **name)
+{
+ char *p;
+ struct mipc_dbi_name *miin2;
+
+ if (len < sizeof(struct mipc_dbi_name))
+ return (MIE_IVAL);
+
+ *miin = (struct mipc_dbi_name *)buf;
+ len -= sizeof(struct mipc_dbi_name);
+ p = buf + sizeof(struct mipc_dbi_name);
+
+ miin2 = *miin;
+
+ if (len < miin2->miin_ilen)
+ return (MIE_IVAL);
+
+ *ident = malloc(miin2->miin_ilen + 1);
+ if (*ident == NULL)
+ return (MIE_INTE);
+ memcpy(*ident, p, miin2->miin_ilen);
+ *ident[miin2->miin_ilen] = '\0';
+ p += miin2->miin_ilen;
+ len -= miin2->miin_ilen;
+
+ if (len < miin2->miin_len) {
+ free(*ident);
+ return (MIE_IVAL);
+ }
+
+ *name = malloc((miin2->miin_len + 1) * sizeof(wchar_t));
+ if (*name == NULL) {
+ free(*ident);
+ return (MIE_IVAL);
+ }
+ memcpy(*name, p, miin2->miin_len * sizeof(wchar_t));
+ *name[miin2->miin_len] = L'\0';
+
+ return (0);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_ADD - Add a name record to a resource identifier
+ */
+static int
+mtpf_name_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct md_glob *g;
+ struct md_if *mif;
+ struct mipc_dbi_name *miin;
+ wchar_t *name;
+ char *ident;
+ int error, retval = 0;
+
+ error = parse_dbi_name(buf, len, &miin, &ident, &name);
+ if (error != 0)
+ return (error);
+
+ g = csc->csc_serv->cs_glob;
+
+ dprintf(DEBUG_CS, "Request to add name %ls to identifier %s, "
+ "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx);
+
+ RW_RLOCK(g, g_lock);
+
+ if (miin->miin_ifidx > g->g_ifs_max)
+ goto error;
+
+ if (miin->miin_ifidx != 0) {
+ mif = g->g_ifs[miin->miin_ifidx];
+ if (mif == NULL)
+ goto error;
+ error = dbr_name_add(&mif->mif_dbr, ident, name);
+ if (error != 0)
+ retval = MIE_NOENT;
+ }
+ else {
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ dbr_name_add(&mif->mif_dbr, ident, name);
+ }
+ }
+
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ free(name);
+ if (retval == 0)
+ send_ack(csc, mih->mih_id);
+ return (retval);
+error:
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ free(name);
+ return (MIE_IVAL);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_DEL - Remove a name from a resource identifier
+ */
+static int
+mtpf_name_del(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct md_glob *g;
+ struct md_if *mif;
+ struct mipc_dbi_name *miin;
+ wchar_t *name;
+ char *ident;
+ int error, retval = 0;
+
+ error = parse_dbi_name(buf, len, &miin, &ident, &name);
+ if (error != 0)
+ return (error);
+
+ g = csc->csc_serv->cs_glob;
+
+ dprintf(DEBUG_CS, "Request to remove name %ls to identifier %s, "
+ "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx);
+
+ RW_RLOCK(g, g_lock);
+
+ if (miin->miin_ifidx > g->g_ifs_max)
+ goto error;
+
+ if (miin->miin_ifidx != 0) {
+ mif = g->g_ifs[miin->miin_ifidx];
+ if (mif == NULL)
+ goto error;
+ error = dbr_name_add(&mif->mif_dbr, ident, name);
+ if (error != 0)
+ retval = MIE_EXISTS;
+ }
+ else {
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ dbr_name_add(&mif->mif_dbr, ident, name);
+ }
+ }
+
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ free(name);
+ if (retval == 0)
+ send_ack(csc, mih->mih_id);
+ return (retval);
+error:
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ free(name);
+ return (error);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_LIST - Return a list of names on an identifier
+ */
+static int
+mtpf_name_list(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct md_glob *g;
+ struct md_if *mif;
+ struct mipc_dbi_name_list *miinl;
+ char *ident, *p;
+ struct dbr_name *dn;
+ int retval = 0;
+ size_t namlen, nlen, i;
+ struct mipc_dbi_name miin;
+ struct mipc_head rmih;
+ struct iovec iov[5];
+
+ if (len < sizeof(struct mipc_dbi_name_list))
+ return (MIE_IVAL);
+
+ miinl = (struct mipc_dbi_name_list *)buf;
+ p = buf + sizeof(struct mipc_dbi_name_list);
+ len -= sizeof(struct mipc_dbi_name_list);
+
+ if (len < miinl->miinl_ilen)
+ return (MIE_IVAL);
+
+ ident = malloc(miinl->miinl_ilen + 0);
+ if (ident == NULL)
+ return (MIE_INTE);
+ memcpy(ident, p, miinl->miinl_ilen);
+ ident[miinl->miinl_ilen] = '\0';
+
+ dprintf(DEBUG_CS, "Request to list names on identifier %s, "
+ "csc=%x, ifidx=%d", ident, csc, miinl->miinl_ifidx);
+
+ if (miinl->miinl_ifidx == 0)
+ return (MIE_IVAL);
+
+ g = csc->csc_serv->cs_glob;
+ RW_RLOCK(g, g_lock);
+
+ mif = g->g_ifs[miinl->miinl_ifidx];
+ if (mif == NULL) {
+ retval = MIE_IVAL;
+ goto out;
+ }
+
+ dn = dbr_name_list(&mif->mif_dbr, ident, &namlen);
+ if (dn == NULL) {
+ retval = MIE_INTE;
+ goto out;
+ }
+
+ miin.miin_ifidx = mif->mif_index;
+ miin.miin_zero = 0;
+
+ RW_UNLOCK(g, g_lock);
+
+ IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT_NAME, 0);
+ iov[0].iov_base = &rmih;
+ iov[0].iov_len = sizeof(struct mipc_head);
+ iov[1].iov_base = &miin;
+ iov[1].iov_len = sizeof(struct mipc_dbi_name);
+ iov[2].iov_base = ident;
+ iov[2].iov_len = miinl->miinl_ilen;
+ miin.miin_ilen = miinl->miinl_ilen;
+
+ for (i = 0; i < namlen; i++) {
+ rmih.mih_msglen = sizeof(struct mipc_head) +
+ sizeof(struct mipc_dbi_name) + miinl->miinl_ilen;
+
+ len = wcslen(dn[i].dn_name);
+ iov[3].iov_base = dn[i].dn_name;
+ iov[3].iov_len = len * sizeof(wchar_t);
+ rmih.mih_msglen += nlen;
+ miin.miin_len = nlen;
+
+ if (dn[i].dn_ename != NULL) {
+ len = wcslen(dn[i].dn_ename);
+ iov[4].iov_base = dn[i].dn_ename;
+ iov[4].iov_len = len * sizeof(wchar_t);
+ rmih.mih_msglen += nlen;
+ miin.miin_elen = nlen;
+ }
+ else {
+ iov[4].iov_base = NULL;
+ iov[4].iov_len = 0;
+ miin.miin_elen = 0;
+ }
+ writev(csc->csc_sock, iov, 5);
+ }
+
+ dbr_name_list_free(dn, namlen);
+ send_ack(csc, mih->mih_id);
+ return (0);
+out:
+ RW_UNLOCK(g, g_lock);
+ free(ident);
+ return (retval);
+}
+
+/*
+ * Parse MIM_IDENT_RES_{ADD,DEL} messages, helper do mtpf_res_{add,del}
+ */
+static int
+parse_res_set(char *buf, size_t len, struct mipc_dbi_res_set **mirs,
+ char **ident, wchar_t **res, char **resptr)
+{
+ struct mipc_dbi_res_set *mirs2;
+ char *p;
+
+ if (len < sizeof(struct mipc_dbi_res_set))
+ return (MIE_IVAL);
+
+ *mirs = (struct mipc_dbi_res_set *)buf;
+ mirs2 = *mirs;
+
+ p = buf + sizeof(struct mipc_dbi_res_set);
+ len -= sizeof(struct mipc_dbi_res_set);
+
+ if (len < mirs2->mirs_ilen)
+ return (MIE_IVAL);
+
+ *ident = malloc(mirs2->mirs_ilen + 1);
+ if (*ident == NULL)
+ return (MIE_INTE);
+ memcpy(*ident, p, mirs2->mirs_ilen);
+ *ident[mirs2->mirs_ilen] = '\0';
+ p += mirs2->mirs_ilen;
+ len -= mirs2->mirs_ilen;
+
+ *res = NULL;
+ *resptr = NULL;
+
+ if (mirs2->mirs_pointer) {
+ if (len < mirs2->mirs_rlen) {
+ free(*ident);
+ return (MIE_IVAL);
+ }
+
+ *resptr = malloc(mirs2->mirs_rlen + 1);
+ if (*resptr == NULL) {
+ free(*ident);
+ return (MIE_IVAL);
+ }
+ memcpy(*resptr, p, mirs2->mirs_rlen);
+ *resptr[mirs2->mirs_rlen] = '\0';
+ }
+ else {
+ if (len < (mirs2->mirs_rlen * sizeof(wchar_t))) {
+ free(*ident);
+ return (MIE_IVAL);
+ }
+
+ *res = malloc((mirs2->mirs_rlen + 1) * sizeof(wchar_t));
+ if (*res == NULL) {
+ free(*ident);
+ return (MIE_INTE);
+ }
+ memcpy(*res, p, mirs2->mirs_rlen * sizeof(wchar_t));
+ *res[mirs2->mirs_rlen] = L'\0';
+ }
+
+ return (0);
+}
+
+/*
+ * IPC MIM_IDENT_RES_ADD - Add a resource to an identifier
+ */
+static int
+mtpf_res_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+ size_t len)
+{
+ struct md_glob *g;
+ struct md_if *mif;
+ struct mipc_dbi_res_set *mirs;
+ wchar_t *rres;
+ char *ident, *resptr;
+ void *res;
+ int error, ptr;
+
+ error = parse_res_set(buf, len, &mirs, &ident, &rres, &resptr);
+ if (error != 0)
+ return (error);
+ res = (rres != NULL) ? (void *)rres : (void *)resptr;
+ ptr = (resptr != NULL);
+
+ g = csc->csc_serv->cs_glob;
+ RW_RLOCK(g, g_lock);
+ if (mirs->mirs_ifidx > g->g_ifs_max)
+ goto out;
+
+ error = 0;
+ if (mirs->mirs_ifidx != 0) {
+ mif = g->g_ifs[mirs->mirs_ifidx];
+ if (mif == NULL)
+ goto out;
+ error = dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class,
+ mirs->mirs_type, mirs->mirs_ttl, res, ptr);
+ }
+ else {
+ TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+ dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class,
+ mirs->mirs_type, mirs->mirs_ttl, res, ptr);
+ }
+ }
+ RW_UNLOCK(g, g_lock);
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list