File Index
Files and directories
Sign in
FILE

ynl.c

File preview with syntax highlighting.

linux-6.19.14/tools/net/ynl/lib/ynl.c C
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2#include <errno.h>
   3#include <poll.h>
   4#include <string.h>
   5#include <stdlib.h>
   6#include <stdio.h>
   7#include <unistd.h>
   8#include <linux/types.h>
   9#include <linux/genetlink.h>
  10#include <sys/socket.h>
  11
  12#include "ynl.h"
  13
  14#define ARRAY_SIZE(arr)		(sizeof(arr) / sizeof(*arr))
  15
  16#define __yerr_msg(yse, _msg...)					\
  17	({								\
  18		struct ynl_error *_yse = (yse);				\
  19									\
  20		if (_yse) {						\
  21			snprintf(_yse->msg, sizeof(_yse->msg) - 1,  _msg); \
  22			_yse->msg[sizeof(_yse->msg) - 1] = 0;		\
  23		}							\
  24	})
  25
  26#define __yerr_code(yse, _code...)		\
  27	({					\
  28		struct ynl_error *_yse = (yse);	\
  29						\
  30		if (_yse) {			\
  31			_yse->code = _code;	\
  32		}				\
  33	})
  34
  35#define __yerr(yse, _code, _msg...)		\
  36	({					\
  37		__yerr_msg(yse, _msg);		\
  38		__yerr_code(yse, _code);	\
  39	})
  40
  41#define __perr(yse, _msg)		__yerr(yse, errno, _msg)
  42
  43#define yerr_msg(_ys, _msg...)		__yerr_msg(&(_ys)->err, _msg)
  44#define yerr(_ys, _code, _msg...)	__yerr(&(_ys)->err, _code, _msg)
  45#define perr(_ys, _msg)			__yerr(&(_ys)->err, errno, _msg)
  46
  47/* -- Netlink boiler plate */
  48static bool
  49ynl_err_walk_is_sel(const struct ynl_policy_nest *policy,
  50		    const struct nlattr *attr)
  51{
  52	unsigned int type = ynl_attr_type(attr);
  53
  54	return policy && type <= policy->max_attr &&
  55		policy->table[type].is_selector;
  56}
  57
  58static const struct ynl_policy_nest *
  59ynl_err_walk_sel_policy(const struct ynl_policy_attr *policy_attr,
  60			const struct nlattr *selector)
  61{
  62	const struct ynl_policy_nest *policy = policy_attr->nest;
  63	const char *sel;
  64	unsigned int i;
  65
  66	if (!policy_attr->is_submsg)
  67		return policy;
  68
  69	sel = ynl_attr_get_str(selector);
  70	for (i = 0; i <= policy->max_attr; i++) {
  71		if (!strcmp(sel, policy->table[i].name))
  72			return policy->table[i].nest;
  73	}
  74
  75	return NULL;
  76}
  77
  78static int
  79ynl_err_walk_report_one(const struct ynl_policy_nest *policy,
  80			const struct nlattr *selector, unsigned int type,
  81			char *str, int str_sz, int *n)
  82{
  83	if (!policy) {
  84		if (*n < str_sz)
  85			*n += snprintf(str, str_sz, "!policy");
  86		return 1;
  87	}
  88
  89	if (type > policy->max_attr) {
  90		if (*n < str_sz)
  91			*n += snprintf(str, str_sz, "!oob");
  92		return 1;
  93	}
  94
  95	if (!policy->table[type].name) {
  96		if (*n < str_sz)
  97			*n += snprintf(str, str_sz, "!name");
  98		return 1;
  99	}
 100
 101	if (*n < str_sz) {
 102		int sz;
 103
 104		sz = snprintf(str, str_sz - *n,
 105			      ".%s", policy->table[type].name);
 106		*n += sz;
 107		str += sz;
 108	}
 109
 110	if (policy->table[type].is_submsg) {
 111		if (!selector) {
 112			if (*n < str_sz)
 113				*n += snprintf(str, str_sz, "(!selector)");
 114			return 1;
 115		}
 116
 117		if (ynl_attr_type(selector) !=
 118		    policy->table[type].selector_type) {
 119			if (*n < str_sz)
 120				*n += snprintf(str, str_sz, "(!=selector)");
 121			return 1;
 122		}
 123
 124		if (*n < str_sz)
 125			*n += snprintf(str, str_sz - *n, "(%s)",
 126				       ynl_attr_get_str(selector));
 127	}
 128
 129	return 0;
 130}
 131
 132static int
 133ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
 134	     const struct ynl_policy_nest *policy, char *str, int str_sz,
 135	     const struct ynl_policy_nest **nest_pol)
 136{
 137	const struct ynl_policy_nest *next_pol;
 138	const struct nlattr *selector = NULL;
 139	unsigned int astart_off, aend_off;
 140	const struct nlattr *attr;
 141	unsigned int data_len;
 142	unsigned int type;
 143	bool found = false;
 144	int n = 0;
 145
 146	if (!policy) {
 147		if (n < str_sz)
 148			n += snprintf(str, str_sz, "!policy");
 149		return n;
 150	}
 151
 152	data_len = end - start;
 153
 154	ynl_attr_for_each_payload(start, data_len, attr) {
 155		astart_off = (char *)attr - (char *)start;
 156		aend_off = (char *)ynl_attr_data_end(attr) - (char *)start;
 157
 158		if (ynl_err_walk_is_sel(policy, attr))
 159			selector = attr;
 160
 161		if (aend_off <= off)
 162			continue;
 163
 164		found = true;
 165		break;
 166	}
 167	if (!found)
 168		return 0;
 169
 170	off -= astart_off;
 171
 172	type = ynl_attr_type(attr);
 173
 174	if (ynl_err_walk_report_one(policy, selector, type, str, str_sz, &n))
 175		return n;
 176
 177	next_pol = ynl_err_walk_sel_policy(&policy->table[type], selector);
 178	if (!next_pol)
 179		return n;
 180
 181	if (!off) {
 182		if (nest_pol)
 183			*nest_pol = next_pol;
 184		return n;
 185	}
 186
 187	if (!next_pol) {
 188		if (n < str_sz)
 189			n += snprintf(str, str_sz, "!nest");
 190		return n;
 191	}
 192
 193	off -= sizeof(struct nlattr);
 194	start =  ynl_attr_data(attr);
 195	end = start + ynl_attr_data_len(attr);
 196
 197	return n + ynl_err_walk(ys, start, end, off, next_pol,
 198				&str[n], str_sz - n, nest_pol);
 199}
 200
 201#define NLMSGERR_ATTR_MISS_TYPE (NLMSGERR_ATTR_POLICY + 1)
 202#define NLMSGERR_ATTR_MISS_NEST (NLMSGERR_ATTR_POLICY + 2)
 203#define NLMSGERR_ATTR_MAX (NLMSGERR_ATTR_MAX + 2)
 204
 205static int
 206ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
 207		  unsigned int hlen)
 208{
 209	const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
 210	char miss_attr[sizeof(ys->err.msg)];
 211	char bad_attr[sizeof(ys->err.msg)];
 212	const struct nlattr *attr;
 213	const char *str = NULL;
 214
 215	if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) {
 216		yerr_msg(ys, "%s", strerror(ys->err.code));
 217		return YNL_PARSE_CB_OK;
 218	}
 219
 220	ynl_attr_for_each(attr, nlh, hlen) {
 221		unsigned int len, type;
 222
 223		len = ynl_attr_data_len(attr);
 224		type = ynl_attr_type(attr);
 225
 226		if (type > NLMSGERR_ATTR_MAX)
 227			continue;
 228
 229		tb[type] = attr;
 230
 231		switch (type) {
 232		case NLMSGERR_ATTR_OFFS:
 233		case NLMSGERR_ATTR_MISS_TYPE:
 234		case NLMSGERR_ATTR_MISS_NEST:
 235			if (len != sizeof(__u32))
 236				return YNL_PARSE_CB_ERROR;
 237			break;
 238		case NLMSGERR_ATTR_MSG:
 239			str = ynl_attr_get_str(attr);
 240			if (str[len - 1])
 241				return YNL_PARSE_CB_ERROR;
 242			break;
 243		default:
 244			break;
 245		}
 246	}
 247
 248	bad_attr[0] = '\0';
 249	miss_attr[0] = '\0';
 250
 251	if (tb[NLMSGERR_ATTR_OFFS]) {
 252		unsigned int n, off;
 253		void *start, *end;
 254
 255		ys->err.attr_offs = ynl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
 256
 257		n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ",
 258			     str ? " (" : "");
 259
 260		start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len);
 261		end = ynl_nlmsg_end_addr(ys->nlh);
 262
 263		off = ys->err.attr_offs;
 264		off -= sizeof(struct nlmsghdr);
 265		off -= ys->req_hdr_len;
 266
 267		n += ynl_err_walk(ys, start, end, off, ys->req_policy,
 268				  &bad_attr[n], sizeof(bad_attr) - n, NULL);
 269
 270		if (n >= sizeof(bad_attr))
 271			n = sizeof(bad_attr) - 1;
 272		bad_attr[n] = '\0';
 273	}
 274	if (tb[NLMSGERR_ATTR_MISS_TYPE]) {
 275		const struct ynl_policy_nest *nest_pol = NULL;
 276		unsigned int n, off, type;
 277		void *start, *end;
 278		int n2;
 279
 280		type = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]);
 281
 282		n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ",
 283			     bad_attr[0] ? ", " : (str ? " (" : ""));
 284
 285		start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len);
 286		end = ynl_nlmsg_end_addr(ys->nlh);
 287
 288		nest_pol = ys->req_policy;
 289		if (tb[NLMSGERR_ATTR_MISS_NEST]) {
 290			off = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
 291			off -= sizeof(struct nlmsghdr);
 292			off -= ys->req_hdr_len;
 293
 294			n += ynl_err_walk(ys, start, end, off, ys->req_policy,
 295					  &miss_attr[n], sizeof(miss_attr) - n,
 296					  &nest_pol);
 297		}
 298
 299		n2 = 0;
 300		ynl_err_walk_report_one(nest_pol, NULL, type, &miss_attr[n],
 301					sizeof(miss_attr) - n, &n2);
 302		n += n2;
 303
 304		if (n >= sizeof(miss_attr))
 305			n = sizeof(miss_attr) - 1;
 306		miss_attr[n] = '\0';
 307	}
 308
 309	/* Implicitly depend on ys->err.code already set */
 310	if (str)
 311		yerr_msg(ys, "Kernel %s: '%s'%s%s%s",
 312			 ys->err.code ? "error" : "warning",
 313			 str, bad_attr, miss_attr,
 314			 bad_attr[0] || miss_attr[0] ? ")" : "");
 315	else if (bad_attr[0] || miss_attr[0])
 316		yerr_msg(ys, "Kernel %s: %s%s",
 317			 ys->err.code ? "error" : "warning",
 318			 bad_attr, miss_attr);
 319	else
 320		yerr_msg(ys, "%s", strerror(ys->err.code));
 321
 322	return YNL_PARSE_CB_OK;
 323}
 324
 325static int
 326ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 327{
 328	const struct nlmsgerr *err = ynl_nlmsg_data(nlh);
 329	unsigned int hlen;
 330	int code;
 331
 332	code = err->error >= 0 ? err->error : -err->error;
 333	yarg->ys->err.code = code;
 334	errno = code;
 335
 336	hlen = sizeof(*err);
 337	if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
 338		hlen += ynl_nlmsg_data_len(&err->msg);
 339
 340	ynl_ext_ack_check(yarg->ys, nlh, hlen);
 341
 342	return code ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_STOP;
 343}
 344
 345static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 346{
 347	int err;
 348
 349	err = *(int *)NLMSG_DATA(nlh);
 350	if (err < 0) {
 351		yarg->ys->err.code = -err;
 352		errno = -err;
 353
 354		ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
 355
 356		return YNL_PARSE_CB_ERROR;
 357	}
 358	return YNL_PARSE_CB_STOP;
 359}
 360
 361/* Attribute validation */
 362
 363int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr,
 364			unsigned int type)
 365{
 366	const struct ynl_policy_attr *policy;
 367	unsigned char *data;
 368	unsigned int len;
 369
 370	data = ynl_attr_data(attr);
 371	len = ynl_attr_data_len(attr);
 372	if (type > yarg->rsp_policy->max_attr) {
 373		yerr(yarg->ys, YNL_ERROR_INTERNAL,
 374		     "Internal error, validating unknown attribute");
 375		return -1;
 376	}
 377
 378	policy = &yarg->rsp_policy->table[type];
 379
 380	switch (policy->type) {
 381	case YNL_PT_REJECT:
 382		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 383		     "Rejected attribute (%s)", policy->name);
 384		return -1;
 385	case YNL_PT_IGNORE:
 386		break;
 387	case YNL_PT_U8:
 388		if (len == sizeof(__u8))
 389			break;
 390		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 391		     "Invalid attribute (u8 %s)", policy->name);
 392		return -1;
 393	case YNL_PT_U16:
 394		if (len == sizeof(__u16))
 395			break;
 396		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 397		     "Invalid attribute (u16 %s)", policy->name);
 398		return -1;
 399	case YNL_PT_U32:
 400		if (len == sizeof(__u32))
 401			break;
 402		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 403		     "Invalid attribute (u32 %s)", policy->name);
 404		return -1;
 405	case YNL_PT_U64:
 406		if (len == sizeof(__u64))
 407			break;
 408		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 409		     "Invalid attribute (u64 %s)", policy->name);
 410		return -1;
 411	case YNL_PT_UINT:
 412		if (len == sizeof(__u32) || len == sizeof(__u64))
 413			break;
 414		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 415		     "Invalid attribute (uint %s)", policy->name);
 416		return -1;
 417	case YNL_PT_FLAG:
 418		/* Let flags grow into real attrs, why not.. */
 419		break;
 420	case YNL_PT_NEST:
 421		if (!len || len >= sizeof(*attr))
 422			break;
 423		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 424		     "Invalid attribute (nest %s)", policy->name);
 425		return -1;
 426	case YNL_PT_BINARY:
 427		if (!policy->len || len == policy->len)
 428			break;
 429		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 430		     "Invalid attribute (binary %s)", policy->name);
 431		return -1;
 432	case YNL_PT_NUL_STR:
 433		if (len && (!policy->len || len <= policy->len) && !data[len - 1])
 434			break;
 435		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 436		     "Invalid attribute (string %s)", policy->name);
 437		return -1;
 438	case YNL_PT_BITFIELD32:
 439		if (len == sizeof(struct nla_bitfield32))
 440			break;
 441		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 442		     "Invalid attribute (bitfield32 %s)", policy->name);
 443		return -1;
 444	default:
 445		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
 446		     "Invalid attribute (unknown %s)", policy->name);
 447		return -1;
 448	}
 449
 450	return 0;
 451}
 452
 453int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name,
 454		      const char *sel_name)
 455{
 456	yerr(yarg->ys, YNL_ERROR_SUBMSG_KEY,
 457	     "Parsing error: Sub-message key not set (msg %s, key %s)",
 458	     field_name, sel_name);
 459	return YNL_PARSE_CB_ERROR;
 460}
 461
 462/* Generic code */
 463
 464static void ynl_err_reset(struct ynl_sock *ys)
 465{
 466	ys->err.code = 0;
 467	ys->err.attr_offs = 0;
 468	ys->err.msg[0] = 0;
 469}
 470
 471struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags)
 472{
 473	struct nlmsghdr *nlh;
 474
 475	ynl_err_reset(ys);
 476
 477	nlh = ys->nlh = ynl_nlmsg_put_header(ys->tx_buf);
 478	nlh->nlmsg_type	= id;
 479	nlh->nlmsg_flags = flags;
 480	nlh->nlmsg_seq = ++ys->seq;
 481
 482	/* This is a local YNL hack for length checking, we put the buffer
 483	 * length in nlmsg_pid, since messages sent to the kernel always use
 484	 * PID 0. Message needs to be terminated with ynl_msg_end().
 485	 */
 486	nlh->nlmsg_pid = YNL_SOCKET_BUFFER_SIZE;
 487
 488	return nlh;
 489}
 490
 491static int ynl_msg_end(struct ynl_sock *ys, struct nlmsghdr *nlh)
 492{
 493	/* We stash buffer length in nlmsg_pid. */
 494	if (nlh->nlmsg_pid == 0) {
 495		yerr(ys, YNL_ERROR_INPUT_INVALID,
 496		     "Unknown input buffer length");
 497		return -EINVAL;
 498	}
 499	if (nlh->nlmsg_pid == YNL_MSG_OVERFLOW) {
 500		yerr(ys, YNL_ERROR_INPUT_TOO_BIG,
 501		     "Constructed message longer than internal buffer");
 502		return -EMSGSIZE;
 503	}
 504
 505	nlh->nlmsg_pid = 0;
 506	return 0;
 507}
 508
 509struct nlmsghdr *
 510ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
 511		__u8 cmd, __u8 version)
 512{
 513	struct genlmsghdr gehdr;
 514	struct nlmsghdr *nlh;
 515	void *data;
 516
 517	nlh = ynl_msg_start(ys, id, flags);
 518
 519	memset(&gehdr, 0, sizeof(gehdr));
 520	gehdr.cmd = cmd;
 521	gehdr.version = version;
 522
 523	data = ynl_nlmsg_put_extra_header(nlh, sizeof(gehdr));
 524	memcpy(data, &gehdr, sizeof(gehdr));
 525
 526	return nlh;
 527}
 528
 529struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id, __u16 flags)
 530{
 531	return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | flags);
 532}
 533
 534struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
 535{
 536	return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
 537}
 538
 539struct nlmsghdr *
 540ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
 541{
 542	return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK, cmd, version);
 543}
 544
 545struct nlmsghdr *
 546ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
 547{
 548	return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
 549			       cmd, version);
 550}
 551
 552static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 553{
 554	yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
 555	     "Received a message when none were expected");
 556
 557	return YNL_PARSE_CB_ERROR;
 558}
 559
 560static int
 561__ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb, int flags)
 562{
 563	struct ynl_sock *ys = yarg->ys;
 564	const struct nlmsghdr *nlh;
 565	ssize_t len, rem;
 566	int ret;
 567
 568	len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, flags);
 569	if (len < 0) {
 570		if (flags & MSG_DONTWAIT && errno == EAGAIN)
 571			return YNL_PARSE_CB_STOP;
 572		return len;
 573	}
 574
 575	ret = YNL_PARSE_CB_STOP;
 576	for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) {
 577		nlh = (struct nlmsghdr *)&ys->rx_buf[len - rem];
 578		if (!NLMSG_OK(nlh, rem)) {
 579			yerr(yarg->ys, YNL_ERROR_INV_RESP,
 580			     "Invalid message or trailing data in the response.");
 581			return YNL_PARSE_CB_ERROR;
 582		}
 583
 584		if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
 585			/* TODO: handle this better */
 586			yerr(yarg->ys, YNL_ERROR_DUMP_INTER,
 587			     "Dump interrupted / inconsistent, please retry.");
 588			return YNL_PARSE_CB_ERROR;
 589		}
 590
 591		switch (nlh->nlmsg_type) {
 592		case 0:
 593			yerr(yarg->ys, YNL_ERROR_INV_RESP,
 594			     "Invalid message type in the response.");
 595			return YNL_PARSE_CB_ERROR;
 596		case NLMSG_NOOP:
 597		case NLMSG_OVERRUN ... NLMSG_MIN_TYPE - 1:
 598			ret = YNL_PARSE_CB_OK;
 599			break;
 600		case NLMSG_ERROR:
 601			ret = ynl_cb_error(nlh, yarg);
 602			break;
 603		case NLMSG_DONE:
 604			ret = ynl_cb_done(nlh, yarg);
 605			break;
 606		default:
 607			ret = cb(nlh, yarg);
 608			break;
 609		}
 610	}
 611
 612	return ret;
 613}
 614
 615static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb)
 616{
 617	return __ynl_sock_read_msgs(yarg, cb, 0);
 618}
 619
 620static int ynl_recv_ack(struct ynl_sock *ys, int ret)
 621{
 622	struct ynl_parse_arg yarg = { .ys = ys, };
 623
 624	if (!ret) {
 625		yerr(ys, YNL_ERROR_EXPECT_ACK,
 626		     "Expecting an ACK but nothing received");
 627		return -1;
 628	}
 629
 630	return ynl_sock_read_msgs(&yarg, ynl_cb_null);
 631}
 632
 633/* Init/fini and genetlink boiler plate */
 634static int
 635ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
 636{
 637	const struct nlattr *entry, *attr;
 638	unsigned int i;
 639
 640	ynl_attr_for_each_nested(attr, mcasts)
 641		ys->n_mcast_groups++;
 642
 643	if (!ys->n_mcast_groups)
 644		return 0;
 645
 646	ys->mcast_groups = calloc(ys->n_mcast_groups,
 647				  sizeof(*ys->mcast_groups));
 648	if (!ys->mcast_groups)
 649		return YNL_PARSE_CB_ERROR;
 650
 651	i = 0;
 652	ynl_attr_for_each_nested(entry, mcasts) {
 653		ynl_attr_for_each_nested(attr, entry) {
 654			if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_ID)
 655				ys->mcast_groups[i].id = ynl_attr_get_u32(attr);
 656			if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) {
 657				strncpy(ys->mcast_groups[i].name,
 658					ynl_attr_get_str(attr),
 659					GENL_NAMSIZ - 1);
 660				ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0;
 661			}
 662		}
 663		i++;
 664	}
 665
 666	return 0;
 667}
 668
 669static int
 670ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 671{
 672	struct ynl_sock *ys = yarg->ys;
 673	const struct nlattr *attr;
 674	bool found_id = true;
 675
 676	ynl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
 677		if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS)
 678			if (ynl_get_family_info_mcast(ys, attr))
 679				return YNL_PARSE_CB_ERROR;
 680
 681		if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID)
 682			continue;
 683
 684		if (ynl_attr_data_len(attr) != sizeof(__u16)) {
 685			yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID");
 686			return YNL_PARSE_CB_ERROR;
 687		}
 688
 689		ys->family_id = ynl_attr_get_u16(attr);
 690		found_id = true;
 691	}
 692
 693	if (!found_id) {
 694		yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing");
 695		return YNL_PARSE_CB_ERROR;
 696	}
 697	return YNL_PARSE_CB_OK;
 698}
 699
 700static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
 701{
 702	struct ynl_parse_arg yarg = { .ys = ys, };
 703	struct nlmsghdr *nlh;
 704	int err;
 705
 706	nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1);
 707	ynl_attr_put_str(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
 708
 709	err = ynl_msg_end(ys, nlh);
 710	if (err < 0)
 711		return err;
 712
 713	err = send(ys->socket, nlh, nlh->nlmsg_len, 0);
 714	if (err < 0) {
 715		perr(ys, "failed to request socket family info");
 716		return err;
 717	}
 718
 719	err = ynl_sock_read_msgs(&yarg, ynl_get_family_info_cb);
 720	if (err < 0) {
 721		free(ys->mcast_groups);
 722		perr(ys, "failed to receive the socket family info - no such family?");
 723		return err;
 724	}
 725
 726	err = ynl_recv_ack(ys, err);
 727	if (err < 0) {
 728		free(ys->mcast_groups);
 729		return err;
 730	}
 731
 732	return 0;
 733}
 734
 735struct ynl_sock *
 736ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
 737{
 738	struct sockaddr_nl addr;
 739	struct ynl_sock *ys;
 740	socklen_t addrlen;
 741	int sock_type;
 742	int one = 1;
 743
 744	ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE);
 745	if (!ys)
 746		return NULL;
 747	memset(ys, 0, sizeof(*ys));
 748
 749	ys->family = yf;
 750	ys->tx_buf = &ys->raw_buf[0];
 751	ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE];
 752	ys->ntf_last_next = &ys->ntf_first;
 753
 754	sock_type = yf->is_classic ? yf->classic_id : NETLINK_GENERIC;
 755
 756	ys->socket = socket(AF_NETLINK, SOCK_RAW, sock_type);
 757	if (ys->socket < 0) {
 758		__perr(yse, "failed to create a netlink socket");
 759		goto err_free_sock;
 760	}
 761
 762	if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_CAP_ACK,
 763		       &one, sizeof(one))) {
 764		__perr(yse, "failed to enable netlink ACK");
 765		goto err_close_sock;
 766	}
 767	if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_EXT_ACK,
 768		       &one, sizeof(one))) {
 769		__perr(yse, "failed to enable netlink ext ACK");
 770		goto err_close_sock;
 771	}
 772
 773	memset(&addr, 0, sizeof(addr));
 774	addr.nl_family = AF_NETLINK;
 775	if (bind(ys->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
 776		__perr(yse, "unable to bind to a socket address");
 777		goto err_close_sock;
 778	}
 779
 780	memset(&addr, 0, sizeof(addr));
 781	addrlen = sizeof(addr);
 782	if (getsockname(ys->socket, (struct sockaddr *)&addr, &addrlen) < 0) {
 783		__perr(yse, "unable to read socket address");
 784		goto err_close_sock;
 785	}
 786	ys->portid = addr.nl_pid;
 787	ys->seq = random();
 788
 789	if (yf->is_classic) {
 790		ys->family_id = yf->classic_id;
 791	} else if (ynl_sock_read_family(ys, yf->name)) {
 792		if (yse)
 793			memcpy(yse, &ys->err, sizeof(*yse));
 794		goto err_close_sock;
 795	}
 796
 797	return ys;
 798
 799err_close_sock:
 800	close(ys->socket);
 801err_free_sock:
 802	free(ys);
 803	return NULL;
 804}
 805
 806void ynl_sock_destroy(struct ynl_sock *ys)
 807{
 808	struct ynl_ntf_base_type *ntf;
 809
 810	close(ys->socket);
 811	while ((ntf = ynl_ntf_dequeue(ys)))
 812		ynl_ntf_free(ntf);
 813	free(ys->mcast_groups);
 814	free(ys);
 815}
 816
 817/* YNL multicast handling */
 818
 819void ynl_ntf_free(struct ynl_ntf_base_type *ntf)
 820{
 821	ntf->free(ntf);
 822}
 823
 824int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
 825{
 826	unsigned int i;
 827	int err;
 828
 829	for (i = 0; i < ys->n_mcast_groups; i++)
 830		if (!strcmp(ys->mcast_groups[i].name, grp_name))
 831			break;
 832	if (i == ys->n_mcast_groups) {
 833		yerr(ys, ENOENT, "Multicast group '%s' not found", grp_name);
 834		return -1;
 835	}
 836
 837	err = setsockopt(ys->socket, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
 838			 &ys->mcast_groups[i].id,
 839			 sizeof(ys->mcast_groups[i].id));
 840	if (err < 0) {
 841		perr(ys, "Subscribing to multicast group failed");
 842		return -1;
 843	}
 844
 845	return 0;
 846}
 847
 848int ynl_socket_get_fd(struct ynl_sock *ys)
 849{
 850	return ys->socket;
 851}
 852
 853struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys)
 854{
 855	struct ynl_ntf_base_type *ntf;
 856
 857	if (!ynl_has_ntf(ys))
 858		return NULL;
 859
 860	ntf = ys->ntf_first;
 861	ys->ntf_first = ntf->next;
 862	if (ys->ntf_last_next == &ntf->next)
 863		ys->ntf_last_next = &ys->ntf_first;
 864
 865	return ntf;
 866}
 867
 868static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
 869{
 870	struct ynl_parse_arg yarg = { .ys = ys, };
 871	const struct ynl_ntf_info *info;
 872	struct ynl_ntf_base_type *rsp;
 873	__u32 cmd;
 874	int ret;
 875
 876	if (ys->family->is_classic) {
 877		cmd = nlh->nlmsg_type;
 878	} else {
 879		struct genlmsghdr *gehdr;
 880
 881		gehdr = ynl_nlmsg_data(nlh);
 882		cmd = gehdr->cmd;
 883	}
 884
 885	if (cmd >= ys->family->ntf_info_size)
 886		return YNL_PARSE_CB_ERROR;
 887	info = &ys->family->ntf_info[cmd];
 888	if (!info->cb)
 889		return YNL_PARSE_CB_ERROR;
 890
 891	rsp = calloc(1, info->alloc_sz);
 892	rsp->free = info->free;
 893	yarg.data = rsp->data;
 894	yarg.rsp_policy = info->policy;
 895
 896	ret = info->cb(nlh, &yarg);
 897	if (ret <= YNL_PARSE_CB_STOP)
 898		goto err_free;
 899
 900	rsp->family = nlh->nlmsg_type;
 901	rsp->cmd = cmd;
 902
 903	*ys->ntf_last_next = rsp;
 904	ys->ntf_last_next = &rsp->next;
 905
 906	return YNL_PARSE_CB_OK;
 907
 908err_free:
 909	info->free(rsp);
 910	return YNL_PARSE_CB_ERROR;
 911}
 912
 913static int
 914ynl_ntf_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 915{
 916	return ynl_ntf_parse(yarg->ys, nlh);
 917}
 918
 919int ynl_ntf_check(struct ynl_sock *ys)
 920{
 921	struct ynl_parse_arg yarg = { .ys = ys, };
 922	int err;
 923
 924	do {
 925		err = __ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline,
 926					   MSG_DONTWAIT);
 927		if (err < 0)
 928			return err;
 929	} while (err > 0);
 930
 931	return 0;
 932}
 933
 934/* YNL specific helpers used by the auto-generated code */
 935
 936struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123);
 937
 938void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
 939{
 940	yerr(ys, YNL_ERROR_UNKNOWN_NTF,
 941	     "Unknown notification message type '%d'", cmd);
 942}
 943
 944int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg)
 945{
 946	yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg);
 947	return YNL_PARSE_CB_ERROR;
 948}
 949
 950static int
 951ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
 952{
 953	if (ys->family->is_classic) {
 954		if (nlh->nlmsg_type != rsp_cmd)
 955			return ynl_ntf_parse(ys, nlh);
 956	} else {
 957		struct genlmsghdr *gehdr;
 958
 959		if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) {
 960			yerr(ys, YNL_ERROR_INV_RESP,
 961			     "Kernel responded with truncated message");
 962			return -1;
 963		}
 964
 965		gehdr = ynl_nlmsg_data(nlh);
 966		if (gehdr->cmd != rsp_cmd)
 967			return ynl_ntf_parse(ys, nlh);
 968	}
 969
 970	return 0;
 971}
 972
 973static
 974int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
 975{
 976	struct ynl_req_state *yrs = (void *)yarg;
 977	int ret;
 978
 979	ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd);
 980	if (ret)
 981		return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
 982
 983	return yrs->cb(nlh, &yrs->yarg);
 984}
 985
 986int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
 987	     struct ynl_req_state *yrs)
 988{
 989	int err;
 990
 991	err = ynl_msg_end(ys, req_nlh);
 992	if (err < 0)
 993		return err;
 994
 995	err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
 996	if (err < 0)
 997		return err;
 998
 999	do {
1000		err = ynl_sock_read_msgs(&yrs->yarg, ynl_req_trampoline);
1001	} while (err > 0);
1002
1003	return err;
1004}
1005
1006static int
1007ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data)
1008{
1009	struct ynl_dump_state *ds = (void *)data;
1010	struct ynl_dump_list_type *obj;
1011	struct ynl_parse_arg yarg = {};
1012	int ret;
1013
1014	ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd);
1015	if (ret)
1016		return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
1017
1018	obj = calloc(1, ds->alloc_sz);
1019	if (!obj)
1020		return YNL_PARSE_CB_ERROR;
1021
1022	if (!ds->first)
1023		ds->first = obj;
1024	if (ds->last)
1025		ds->last->next = obj;
1026	ds->last = obj;
1027
1028	yarg = ds->yarg;
1029	yarg.data = &obj->data;
1030
1031	return ds->cb(nlh, &yarg);
1032}
1033
1034static void *ynl_dump_end(struct ynl_dump_state *ds)
1035{
1036	if (!ds->first)
1037		return YNL_LIST_END;
1038
1039	ds->last->next = YNL_LIST_END;
1040	return ds->first;
1041}
1042
1043int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
1044		  struct ynl_dump_state *yds)
1045{
1046	int err;
1047
1048	err = ynl_msg_end(ys, req_nlh);
1049	if (err < 0)
1050		return err;
1051
1052	err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
1053	if (err < 0)
1054		return err;
1055
1056	do {
1057		err = ynl_sock_read_msgs(&yds->yarg, ynl_dump_trampoline);
1058		if (err < 0)
1059			goto err_close_list;
1060	} while (err > 0);
1061
1062	yds->first = ynl_dump_end(yds);
1063	return 0;
1064
1065err_close_list:
1066	yds->first = ynl_dump_end(yds);
1067	return -1;
1068}
~/ Read-only file preview.