PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/external/iproute2/lib/libnetlink.c

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
C | 682 lines | 580 code | 89 blank | 13 comment | 123 complexity | 972aa55ff0cbeb5b364d694d8600e469 MD5 | raw file
  1. /*
  2. * libnetlink.c RTnetlink service routines.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version
  7. * 2 of the License, or (at your option) any later version.
  8. *
  9. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10. *
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <syslog.h>
  16. #include <fcntl.h>
  17. #include <net/if_arp.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <time.h>
  23. #include <sys/uio.h>
  24. #include "libnetlink.h"
  25. int rcvbuf = 1024 * 1024;
  26. void rtnl_close(struct rtnl_handle *rth)
  27. {
  28. if (rth->fd >= 0) {
  29. close(rth->fd);
  30. rth->fd = -1;
  31. }
  32. }
  33. int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
  34. int protocol)
  35. {
  36. socklen_t addr_len;
  37. int sndbuf = 32768;
  38. memset(rth, 0, sizeof(*rth));
  39. rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
  40. if (rth->fd < 0) {
  41. perror("Cannot open netlink socket");
  42. return -1;
  43. }
  44. if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
  45. perror("SO_SNDBUF");
  46. return -1;
  47. }
  48. if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
  49. perror("SO_RCVBUF");
  50. return -1;
  51. }
  52. memset(&rth->local, 0, sizeof(rth->local));
  53. rth->local.nl_family = AF_NETLINK;
  54. rth->local.nl_groups = subscriptions;
  55. if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
  56. perror("Cannot bind netlink socket");
  57. return -1;
  58. }
  59. addr_len = sizeof(rth->local);
  60. if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
  61. perror("Cannot getsockname");
  62. return -1;
  63. }
  64. if (addr_len != sizeof(rth->local)) {
  65. fprintf(stderr, "Wrong address length %d\n", addr_len);
  66. return -1;
  67. }
  68. if (rth->local.nl_family != AF_NETLINK) {
  69. fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
  70. return -1;
  71. }
  72. rth->seq = time(NULL);
  73. return 0;
  74. }
  75. int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
  76. {
  77. return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
  78. }
  79. int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
  80. {
  81. struct {
  82. struct nlmsghdr nlh;
  83. struct rtgenmsg g;
  84. } req;
  85. memset(&req, 0, sizeof(req));
  86. req.nlh.nlmsg_len = sizeof(req);
  87. req.nlh.nlmsg_type = type;
  88. req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
  89. req.nlh.nlmsg_pid = 0;
  90. req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  91. req.g.rtgen_family = family;
  92. return send(rth->fd, (void*)&req, sizeof(req), 0);
  93. }
  94. int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
  95. {
  96. return send(rth->fd, buf, len, 0);
  97. }
  98. int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
  99. {
  100. struct nlmsghdr *h;
  101. int status;
  102. char resp[1024];
  103. status = send(rth->fd, buf, len, 0);
  104. if (status < 0)
  105. return status;
  106. /* Check for immediate errors */
  107. status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
  108. if (status < 0) {
  109. if (errno == EAGAIN)
  110. return 0;
  111. return -1;
  112. }
  113. for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
  114. h = NLMSG_NEXT(h, status)) {
  115. if (h->nlmsg_type == NLMSG_ERROR) {
  116. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  117. if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
  118. fprintf(stderr, "ERROR truncated\n");
  119. else
  120. errno = -err->error;
  121. return -1;
  122. }
  123. }
  124. return 0;
  125. }
  126. int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
  127. {
  128. struct nlmsghdr nlh;
  129. struct sockaddr_nl nladdr;
  130. struct iovec iov[2] = {
  131. { .iov_base = &nlh, .iov_len = sizeof(nlh) },
  132. { .iov_base = req, .iov_len = len }
  133. };
  134. struct msghdr msg = {
  135. .msg_name = &nladdr,
  136. .msg_namelen = sizeof(nladdr),
  137. .msg_iov = iov,
  138. .msg_iovlen = 2,
  139. };
  140. memset(&nladdr, 0, sizeof(nladdr));
  141. nladdr.nl_family = AF_NETLINK;
  142. nlh.nlmsg_len = NLMSG_LENGTH(len);
  143. nlh.nlmsg_type = type;
  144. nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
  145. nlh.nlmsg_pid = 0;
  146. nlh.nlmsg_seq = rth->dump = ++rth->seq;
  147. return sendmsg(rth->fd, &msg, 0);
  148. }
  149. int rtnl_dump_filter_l(struct rtnl_handle *rth,
  150. const struct rtnl_dump_filter_arg *arg)
  151. {
  152. struct sockaddr_nl nladdr;
  153. struct iovec iov;
  154. struct msghdr msg = {
  155. .msg_name = &nladdr,
  156. .msg_namelen = sizeof(nladdr),
  157. .msg_iov = &iov,
  158. .msg_iovlen = 1,
  159. };
  160. char buf[16384];
  161. iov.iov_base = buf;
  162. while (1) {
  163. int status;
  164. const struct rtnl_dump_filter_arg *a;
  165. iov.iov_len = sizeof(buf);
  166. status = recvmsg(rth->fd, &msg, 0);
  167. if (status < 0) {
  168. if (errno == EINTR || errno == EAGAIN)
  169. continue;
  170. fprintf(stderr, "netlink receive error %s (%d)\n",
  171. strerror(errno), errno);
  172. return -1;
  173. }
  174. if (status == 0) {
  175. fprintf(stderr, "EOF on netlink\n");
  176. return -1;
  177. }
  178. for (a = arg; a->filter; a++) {
  179. struct nlmsghdr *h = (struct nlmsghdr*)buf;
  180. while (NLMSG_OK(h, status)) {
  181. int err;
  182. if (nladdr.nl_pid != 0 ||
  183. h->nlmsg_pid != rth->local.nl_pid ||
  184. h->nlmsg_seq != rth->dump) {
  185. if (a->junk) {
  186. err = a->junk(&nladdr, h,
  187. a->arg2);
  188. if (err < 0)
  189. return err;
  190. }
  191. goto skip_it;
  192. }
  193. if (h->nlmsg_type == NLMSG_DONE)
  194. return 0;
  195. if (h->nlmsg_type == NLMSG_ERROR) {
  196. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  197. if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
  198. fprintf(stderr,
  199. "ERROR truncated\n");
  200. } else {
  201. errno = -err->error;
  202. perror("RTNETLINK answers");
  203. }
  204. return -1;
  205. }
  206. err = a->filter(&nladdr, h, a->arg1);
  207. if (err < 0)
  208. return err;
  209. skip_it:
  210. h = NLMSG_NEXT(h, status);
  211. }
  212. } while (0);
  213. if (msg.msg_flags & MSG_TRUNC) {
  214. fprintf(stderr, "Message truncated\n");
  215. continue;
  216. }
  217. if (status) {
  218. fprintf(stderr, "!!!Remnant of size %d\n", status);
  219. exit(1);
  220. }
  221. }
  222. }
  223. int rtnl_dump_filter(struct rtnl_handle *rth,
  224. rtnl_filter_t filter,
  225. void *arg1,
  226. rtnl_filter_t junk,
  227. void *arg2)
  228. {
  229. const struct rtnl_dump_filter_arg a[2] = {
  230. { .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 },
  231. { .filter = NULL, .arg1 = NULL, .junk = NULL, .arg2 = NULL }
  232. };
  233. return rtnl_dump_filter_l(rth, a);
  234. }
  235. int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
  236. unsigned groups, struct nlmsghdr *answer,
  237. rtnl_filter_t junk,
  238. void *jarg)
  239. {
  240. int status;
  241. unsigned seq;
  242. struct nlmsghdr *h;
  243. struct sockaddr_nl nladdr;
  244. struct iovec iov = {
  245. .iov_base = (void*) n,
  246. .iov_len = n->nlmsg_len
  247. };
  248. struct msghdr msg = {
  249. .msg_name = &nladdr,
  250. .msg_namelen = sizeof(nladdr),
  251. .msg_iov = &iov,
  252. .msg_iovlen = 1,
  253. };
  254. char buf[16384];
  255. memset(&nladdr, 0, sizeof(nladdr));
  256. nladdr.nl_family = AF_NETLINK;
  257. nladdr.nl_pid = peer;
  258. nladdr.nl_groups = groups;
  259. n->nlmsg_seq = seq = ++rtnl->seq;
  260. if (answer == NULL)
  261. n->nlmsg_flags |= NLM_F_ACK;
  262. status = sendmsg(rtnl->fd, &msg, 0);
  263. if (status < 0) {
  264. perror("Cannot talk to rtnetlink");
  265. return -1;
  266. }
  267. memset(buf,0,sizeof(buf));
  268. iov.iov_base = buf;
  269. while (1) {
  270. iov.iov_len = sizeof(buf);
  271. status = recvmsg(rtnl->fd, &msg, 0);
  272. if (status < 0) {
  273. if (errno == EINTR || errno == EAGAIN)
  274. continue;
  275. fprintf(stderr, "netlink receive error %s (%d)\n",
  276. strerror(errno), errno);
  277. return -1;
  278. }
  279. if (status == 0) {
  280. fprintf(stderr, "EOF on netlink\n");
  281. return -1;
  282. }
  283. if (msg.msg_namelen != sizeof(nladdr)) {
  284. fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
  285. exit(1);
  286. }
  287. for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
  288. int err;
  289. int len = h->nlmsg_len;
  290. int l = len - sizeof(*h);
  291. if (l<0 || len>status) {
  292. if (msg.msg_flags & MSG_TRUNC) {
  293. fprintf(stderr, "Truncated message\n");
  294. return -1;
  295. }
  296. fprintf(stderr, "!!!malformed message: len=%d\n", len);
  297. exit(1);
  298. }
  299. if (nladdr.nl_pid != peer ||
  300. h->nlmsg_pid != rtnl->local.nl_pid ||
  301. h->nlmsg_seq != seq) {
  302. if (junk) {
  303. err = junk(&nladdr, h, jarg);
  304. if (err < 0)
  305. return err;
  306. }
  307. /* Don't forget to skip that message. */
  308. status -= NLMSG_ALIGN(len);
  309. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  310. continue;
  311. }
  312. if (h->nlmsg_type == NLMSG_ERROR) {
  313. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  314. if (l < sizeof(struct nlmsgerr)) {
  315. fprintf(stderr, "ERROR truncated\n");
  316. } else {
  317. errno = -err->error;
  318. if (errno == 0) {
  319. if (answer)
  320. memcpy(answer, h, h->nlmsg_len);
  321. return 0;
  322. }
  323. perror("RTNETLINK answers");
  324. }
  325. return -1;
  326. }
  327. if (answer) {
  328. memcpy(answer, h, h->nlmsg_len);
  329. return 0;
  330. }
  331. fprintf(stderr, "Unexpected reply!!!\n");
  332. status -= NLMSG_ALIGN(len);
  333. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  334. }
  335. if (msg.msg_flags & MSG_TRUNC) {
  336. fprintf(stderr, "Message truncated\n");
  337. continue;
  338. }
  339. if (status) {
  340. fprintf(stderr, "!!!Remnant of size %d\n", status);
  341. exit(1);
  342. }
  343. }
  344. }
  345. int rtnl_listen(struct rtnl_handle *rtnl,
  346. rtnl_filter_t handler,
  347. void *jarg)
  348. {
  349. int status;
  350. struct nlmsghdr *h;
  351. struct sockaddr_nl nladdr;
  352. struct iovec iov;
  353. struct msghdr msg = {
  354. .msg_name = &nladdr,
  355. .msg_namelen = sizeof(nladdr),
  356. .msg_iov = &iov,
  357. .msg_iovlen = 1,
  358. };
  359. char buf[8192];
  360. memset(&nladdr, 0, sizeof(nladdr));
  361. nladdr.nl_family = AF_NETLINK;
  362. nladdr.nl_pid = 0;
  363. nladdr.nl_groups = 0;
  364. iov.iov_base = buf;
  365. while (1) {
  366. iov.iov_len = sizeof(buf);
  367. status = recvmsg(rtnl->fd, &msg, 0);
  368. if (status < 0) {
  369. if (errno == EINTR || errno == EAGAIN)
  370. continue;
  371. fprintf(stderr, "netlink receive error %s (%d)\n",
  372. strerror(errno), errno);
  373. if (errno == ENOBUFS)
  374. continue;
  375. return -1;
  376. }
  377. if (status == 0) {
  378. fprintf(stderr, "EOF on netlink\n");
  379. return -1;
  380. }
  381. if (msg.msg_namelen != sizeof(nladdr)) {
  382. fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
  383. exit(1);
  384. }
  385. for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
  386. int err;
  387. int len = h->nlmsg_len;
  388. int l = len - sizeof(*h);
  389. if (l<0 || len>status) {
  390. if (msg.msg_flags & MSG_TRUNC) {
  391. fprintf(stderr, "Truncated message\n");
  392. return -1;
  393. }
  394. fprintf(stderr, "!!!malformed message: len=%d\n", len);
  395. exit(1);
  396. }
  397. err = handler(&nladdr, h, jarg);
  398. if (err < 0)
  399. return err;
  400. status -= NLMSG_ALIGN(len);
  401. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  402. }
  403. if (msg.msg_flags & MSG_TRUNC) {
  404. fprintf(stderr, "Message truncated\n");
  405. continue;
  406. }
  407. if (status) {
  408. fprintf(stderr, "!!!Remnant of size %d\n", status);
  409. exit(1);
  410. }
  411. }
  412. }
  413. int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
  414. void *jarg)
  415. {
  416. int status;
  417. struct sockaddr_nl nladdr;
  418. char buf[8192];
  419. struct nlmsghdr *h = (void*)buf;
  420. memset(&nladdr, 0, sizeof(nladdr));
  421. nladdr.nl_family = AF_NETLINK;
  422. nladdr.nl_pid = 0;
  423. nladdr.nl_groups = 0;
  424. while (1) {
  425. int err, len, type;
  426. int l;
  427. status = fread(&buf, 1, sizeof(*h), rtnl);
  428. if (status < 0) {
  429. if (errno == EINTR)
  430. continue;
  431. perror("rtnl_from_file: fread");
  432. return -1;
  433. }
  434. if (status == 0)
  435. return 0;
  436. len = h->nlmsg_len;
  437. type= h->nlmsg_type;
  438. l = len - sizeof(*h);
  439. if (l<0 || len>sizeof(buf)) {
  440. fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
  441. len, ftell(rtnl));
  442. return -1;
  443. }
  444. status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
  445. if (status < 0) {
  446. perror("rtnl_from_file: fread");
  447. return -1;
  448. }
  449. if (status < l) {
  450. fprintf(stderr, "rtnl-from_file: truncated message\n");
  451. return -1;
  452. }
  453. err = handler(&nladdr, h, jarg);
  454. if (err < 0)
  455. return err;
  456. }
  457. }
  458. int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
  459. {
  460. int len = RTA_LENGTH(4);
  461. struct rtattr *rta;
  462. if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
  463. fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
  464. return -1;
  465. }
  466. rta = NLMSG_TAIL(n);
  467. rta->rta_type = type;
  468. rta->rta_len = len;
  469. memcpy(RTA_DATA(rta), &data, 4);
  470. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
  471. return 0;
  472. }
  473. int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
  474. int alen)
  475. {
  476. int len = RTA_LENGTH(alen);
  477. struct rtattr *rta;
  478. if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
  479. fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
  480. return -1;
  481. }
  482. rta = NLMSG_TAIL(n);
  483. rta->rta_type = type;
  484. rta->rta_len = len;
  485. memcpy(RTA_DATA(rta), data, alen);
  486. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
  487. return 0;
  488. }
  489. int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
  490. {
  491. if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
  492. fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
  493. return -1;
  494. }
  495. memcpy(NLMSG_TAIL(n), data, len);
  496. memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
  497. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
  498. return 0;
  499. }
  500. struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
  501. {
  502. struct rtattr *nest = NLMSG_TAIL(n);
  503. addattr_l(n, maxlen, type, NULL, 0);
  504. return nest;
  505. }
  506. int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
  507. {
  508. nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
  509. return n->nlmsg_len;
  510. }
  511. struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
  512. const void *data, int len)
  513. {
  514. struct rtattr *start = NLMSG_TAIL(n);
  515. addattr_l(n, maxlen, type, data, len);
  516. addattr_nest(n, maxlen, type);
  517. return start;
  518. }
  519. int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
  520. {
  521. struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
  522. start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
  523. addattr_nest_end(n, nest);
  524. return n->nlmsg_len;
  525. }
  526. int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
  527. {
  528. int len = RTA_LENGTH(4);
  529. struct rtattr *subrta;
  530. if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
  531. fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
  532. return -1;
  533. }
  534. subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
  535. subrta->rta_type = type;
  536. subrta->rta_len = len;
  537. memcpy(RTA_DATA(subrta), &data, 4);
  538. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
  539. return 0;
  540. }
  541. int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
  542. const void *data, int alen)
  543. {
  544. struct rtattr *subrta;
  545. int len = RTA_LENGTH(alen);
  546. if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
  547. fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
  548. return -1;
  549. }
  550. subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
  551. subrta->rta_type = type;
  552. subrta->rta_len = len;
  553. memcpy(RTA_DATA(subrta), data, alen);
  554. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
  555. return 0;
  556. }
  557. int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
  558. {
  559. memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
  560. while (RTA_OK(rta, len)) {
  561. if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
  562. tb[rta->rta_type] = rta;
  563. rta = RTA_NEXT(rta,len);
  564. }
  565. if (len)
  566. fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  567. return 0;
  568. }
  569. int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
  570. {
  571. int i = 0;
  572. memset(tb, 0, sizeof(struct rtattr *) * max);
  573. while (RTA_OK(rta, len)) {
  574. if (rta->rta_type <= max && i < max)
  575. tb[i++] = rta;
  576. rta = RTA_NEXT(rta,len);
  577. }
  578. if (len)
  579. fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  580. return i;
  581. }
  582. int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
  583. int len)
  584. {
  585. if (RTA_PAYLOAD(rta) < len)
  586. return -1;
  587. if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
  588. rta = RTA_DATA(rta) + RTA_ALIGN(len);
  589. return parse_rtattr_nested(tb, max, rta);
  590. }
  591. memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
  592. return 0;
  593. }