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