PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/external/iproute2/lib/libnetlink.c

https://gitlab.com/abhishekr700/ASUS_ZenFone_ZE550KL
C | 691 lines | 582 code | 96 blank | 13 comment | 118 complexity | f63f9576789cecbf9d0053b28656e174 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. __u16 align_rta; /* attribute has to be 32bit aligned */
  85. struct rtattr ext_req;
  86. __u32 ext_filter_mask;
  87. } req;
  88. memset(&req, 0, sizeof(req));
  89. req.nlh.nlmsg_len = sizeof(req);
  90. req.nlh.nlmsg_type = type;
  91. req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
  92. req.nlh.nlmsg_pid = 0;
  93. req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  94. req.g.rtgen_family = family;
  95. req.ext_req.rta_type = IFLA_EXT_MASK;
  96. req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32));
  97. req.ext_filter_mask = RTEXT_FILTER_VF;
  98. return send(rth->fd, (void*)&req, sizeof(req), 0);
  99. }
  100. int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
  101. {
  102. return send(rth->fd, buf, len, 0);
  103. }
  104. int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
  105. {
  106. struct nlmsghdr *h;
  107. int status;
  108. char resp[1024];
  109. status = send(rth->fd, buf, len, 0);
  110. if (status < 0)
  111. return status;
  112. /* Check for immediate errors */
  113. status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
  114. if (status < 0) {
  115. if (errno == EAGAIN)
  116. return 0;
  117. return -1;
  118. }
  119. for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
  120. h = NLMSG_NEXT(h, status)) {
  121. if (h->nlmsg_type == NLMSG_ERROR) {
  122. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  123. if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
  124. fprintf(stderr, "ERROR truncated\n");
  125. else
  126. errno = -err->error;
  127. return -1;
  128. }
  129. }
  130. return 0;
  131. }
  132. int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
  133. {
  134. struct nlmsghdr nlh;
  135. struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
  136. struct iovec iov[2] = {
  137. { .iov_base = &nlh, .iov_len = sizeof(nlh) },
  138. { .iov_base = req, .iov_len = len }
  139. };
  140. struct msghdr msg = {
  141. .msg_name = &nladdr,
  142. .msg_namelen = sizeof(nladdr),
  143. .msg_iov = iov,
  144. .msg_iovlen = 2,
  145. };
  146. nlh.nlmsg_len = NLMSG_LENGTH(len);
  147. nlh.nlmsg_type = type;
  148. nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
  149. nlh.nlmsg_pid = 0;
  150. nlh.nlmsg_seq = rth->dump = ++rth->seq;
  151. return sendmsg(rth->fd, &msg, 0);
  152. }
  153. int rtnl_dump_filter_l(struct rtnl_handle *rth,
  154. const struct rtnl_dump_filter_arg *arg)
  155. {
  156. struct sockaddr_nl nladdr;
  157. struct iovec iov;
  158. struct msghdr msg = {
  159. .msg_name = &nladdr,
  160. .msg_namelen = sizeof(nladdr),
  161. .msg_iov = &iov,
  162. .msg_iovlen = 1,
  163. };
  164. char buf[16384];
  165. iov.iov_base = buf;
  166. while (1) {
  167. int status;
  168. const struct rtnl_dump_filter_arg *a;
  169. int found_done = 0;
  170. int msglen = 0;
  171. iov.iov_len = sizeof(buf);
  172. status = recvmsg(rth->fd, &msg, 0);
  173. if (status < 0) {
  174. if (errno == EINTR || errno == EAGAIN)
  175. continue;
  176. fprintf(stderr, "netlink receive error %s (%d)\n",
  177. strerror(errno), errno);
  178. return -1;
  179. }
  180. if (status == 0) {
  181. fprintf(stderr, "EOF on netlink\n");
  182. return -1;
  183. }
  184. for (a = arg; a->filter; a++) {
  185. struct nlmsghdr *h = (struct nlmsghdr*)buf;
  186. msglen = status;
  187. while (NLMSG_OK(h, msglen)) {
  188. int err;
  189. if (nladdr.nl_pid != 0 ||
  190. h->nlmsg_pid != rth->local.nl_pid ||
  191. h->nlmsg_seq != rth->dump)
  192. goto skip_it;
  193. if (h->nlmsg_type == NLMSG_DONE) {
  194. found_done = 1;
  195. break; /* process next filter */
  196. }
  197. if (h->nlmsg_type == NLMSG_ERROR) {
  198. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  199. if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
  200. fprintf(stderr,
  201. "ERROR truncated\n");
  202. } else {
  203. errno = -err->error;
  204. perror("RTNETLINK answers");
  205. }
  206. return -1;
  207. }
  208. err = a->filter(&nladdr, h, a->arg1);
  209. if (err < 0)
  210. return err;
  211. skip_it:
  212. h = NLMSG_NEXT(h, msglen);
  213. }
  214. }
  215. if (found_done)
  216. return 0;
  217. if (msg.msg_flags & MSG_TRUNC) {
  218. fprintf(stderr, "Message truncated\n");
  219. continue;
  220. }
  221. if (msglen) {
  222. fprintf(stderr, "!!!Remnant of size %d\n", msglen);
  223. exit(1);
  224. }
  225. }
  226. }
  227. int rtnl_dump_filter(struct rtnl_handle *rth,
  228. rtnl_filter_t filter,
  229. void *arg1)
  230. {
  231. const struct rtnl_dump_filter_arg a[2] = {
  232. { .filter = filter, .arg1 = arg1, },
  233. { .filter = NULL, .arg1 = NULL, },
  234. };
  235. return rtnl_dump_filter_l(rth, a);
  236. }
  237. int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
  238. unsigned groups, struct nlmsghdr *answer)
  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 len = h->nlmsg_len;
  289. int l = len - sizeof(*h);
  290. if (l < 0 || len>status) {
  291. if (msg.msg_flags & MSG_TRUNC) {
  292. fprintf(stderr, "Truncated message\n");
  293. return -1;
  294. }
  295. fprintf(stderr, "!!!malformed message: len=%d\n", len);
  296. exit(1);
  297. }
  298. if (nladdr.nl_pid != peer ||
  299. h->nlmsg_pid != rtnl->local.nl_pid ||
  300. h->nlmsg_seq != seq) {
  301. /* Don't forget to skip that message. */
  302. status -= NLMSG_ALIGN(len);
  303. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  304. continue;
  305. }
  306. if (h->nlmsg_type == NLMSG_ERROR) {
  307. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  308. if (l < sizeof(struct nlmsgerr)) {
  309. fprintf(stderr, "ERROR truncated\n");
  310. } else {
  311. errno = -err->error;
  312. if (errno == 0) {
  313. if (answer)
  314. memcpy(answer, h, h->nlmsg_len);
  315. return 0;
  316. }
  317. perror("RTNETLINK answers");
  318. }
  319. return -1;
  320. }
  321. if (answer) {
  322. memcpy(answer, h, h->nlmsg_len);
  323. return 0;
  324. }
  325. fprintf(stderr, "Unexpected reply!!!\n");
  326. status -= NLMSG_ALIGN(len);
  327. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  328. }
  329. if (msg.msg_flags & MSG_TRUNC) {
  330. fprintf(stderr, "Message truncated\n");
  331. continue;
  332. }
  333. if (status) {
  334. fprintf(stderr, "!!!Remnant of size %d\n", status);
  335. exit(1);
  336. }
  337. }
  338. }
  339. int rtnl_listen(struct rtnl_handle *rtnl,
  340. rtnl_filter_t handler,
  341. void *jarg)
  342. {
  343. int status;
  344. struct nlmsghdr *h;
  345. struct sockaddr_nl nladdr;
  346. struct iovec iov;
  347. struct msghdr msg = {
  348. .msg_name = &nladdr,
  349. .msg_namelen = sizeof(nladdr),
  350. .msg_iov = &iov,
  351. .msg_iovlen = 1,
  352. };
  353. char buf[8192];
  354. memset(&nladdr, 0, sizeof(nladdr));
  355. nladdr.nl_family = AF_NETLINK;
  356. nladdr.nl_pid = 0;
  357. nladdr.nl_groups = 0;
  358. iov.iov_base = buf;
  359. while (1) {
  360. iov.iov_len = sizeof(buf);
  361. status = recvmsg(rtnl->fd, &msg, 0);
  362. if (status < 0) {
  363. if (errno == EINTR || errno == EAGAIN)
  364. continue;
  365. fprintf(stderr, "netlink receive error %s (%d)\n",
  366. strerror(errno), errno);
  367. if (errno == ENOBUFS)
  368. continue;
  369. return -1;
  370. }
  371. if (status == 0) {
  372. fprintf(stderr, "EOF on netlink\n");
  373. return -1;
  374. }
  375. if (msg.msg_namelen != sizeof(nladdr)) {
  376. fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
  377. exit(1);
  378. }
  379. for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
  380. int err;
  381. int len = h->nlmsg_len;
  382. int l = len - sizeof(*h);
  383. if (l<0 || len>status) {
  384. if (msg.msg_flags & MSG_TRUNC) {
  385. fprintf(stderr, "Truncated message\n");
  386. return -1;
  387. }
  388. fprintf(stderr, "!!!malformed message: len=%d\n", len);
  389. exit(1);
  390. }
  391. err = handler(&nladdr, h, jarg);
  392. if (err < 0)
  393. return err;
  394. status -= NLMSG_ALIGN(len);
  395. h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
  396. }
  397. if (msg.msg_flags & MSG_TRUNC) {
  398. fprintf(stderr, "Message truncated\n");
  399. continue;
  400. }
  401. if (status) {
  402. fprintf(stderr, "!!!Remnant of size %d\n", status);
  403. exit(1);
  404. }
  405. }
  406. }
  407. int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
  408. void *jarg)
  409. {
  410. int status;
  411. struct sockaddr_nl nladdr;
  412. char buf[8192];
  413. struct nlmsghdr *h = (void*)buf;
  414. memset(&nladdr, 0, sizeof(nladdr));
  415. nladdr.nl_family = AF_NETLINK;
  416. nladdr.nl_pid = 0;
  417. nladdr.nl_groups = 0;
  418. while (1) {
  419. int err, len;
  420. int l;
  421. status = fread(&buf, 1, sizeof(*h), rtnl);
  422. if (status < 0) {
  423. if (errno == EINTR)
  424. continue;
  425. perror("rtnl_from_file: fread");
  426. return -1;
  427. }
  428. if (status == 0)
  429. return 0;
  430. len = h->nlmsg_len;
  431. l = len - sizeof(*h);
  432. if (l<0 || len>sizeof(buf)) {
  433. fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
  434. len, ftell(rtnl));
  435. return -1;
  436. }
  437. status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
  438. if (status < 0) {
  439. perror("rtnl_from_file: fread");
  440. return -1;
  441. }
  442. if (status < l) {
  443. fprintf(stderr, "rtnl-from_file: truncated message\n");
  444. return -1;
  445. }
  446. err = handler(&nladdr, h, jarg);
  447. if (err < 0)
  448. return err;
  449. }
  450. }
  451. int addattr(struct nlmsghdr *n, int maxlen, int type)
  452. {
  453. return addattr_l(n, maxlen, type, NULL, 0);
  454. }
  455. int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
  456. {
  457. return addattr_l(n, maxlen, type, &data, sizeof(__u8));
  458. }
  459. int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
  460. {
  461. return addattr_l(n, maxlen, type, &data, sizeof(__u16));
  462. }
  463. int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
  464. {
  465. return addattr_l(n, maxlen, type, &data, sizeof(__u32));
  466. }
  467. int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
  468. {
  469. return addattr_l(n, maxlen, type, &data, sizeof(__u64));
  470. }
  471. int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
  472. {
  473. return addattr_l(n, maxlen, type, str, strlen(str)+1);
  474. }
  475. int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
  476. int alen)
  477. {
  478. int len = RTA_LENGTH(alen);
  479. struct rtattr *rta;
  480. if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
  481. fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
  482. return -1;
  483. }
  484. rta = NLMSG_TAIL(n);
  485. rta->rta_type = type;
  486. rta->rta_len = len;
  487. memcpy(RTA_DATA(rta), data, alen);
  488. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
  489. return 0;
  490. }
  491. int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
  492. {
  493. if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
  494. fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
  495. return -1;
  496. }
  497. memcpy(NLMSG_TAIL(n), data, len);
  498. memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
  499. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
  500. return 0;
  501. }
  502. struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
  503. {
  504. struct rtattr *nest = NLMSG_TAIL(n);
  505. addattr_l(n, maxlen, type, NULL, 0);
  506. return nest;
  507. }
  508. int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
  509. {
  510. nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
  511. return n->nlmsg_len;
  512. }
  513. struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
  514. const void *data, int len)
  515. {
  516. struct rtattr *start = NLMSG_TAIL(n);
  517. addattr_l(n, maxlen, type, data, len);
  518. addattr_nest(n, maxlen, type);
  519. return start;
  520. }
  521. int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
  522. {
  523. struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
  524. start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
  525. addattr_nest_end(n, nest);
  526. return n->nlmsg_len;
  527. }
  528. int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
  529. {
  530. int len = RTA_LENGTH(4);
  531. struct rtattr *subrta;
  532. if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
  533. fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
  534. return -1;
  535. }
  536. subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
  537. subrta->rta_type = type;
  538. subrta->rta_len = len;
  539. memcpy(RTA_DATA(subrta), &data, 4);
  540. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
  541. return 0;
  542. }
  543. int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
  544. const void *data, int alen)
  545. {
  546. struct rtattr *subrta;
  547. int len = RTA_LENGTH(alen);
  548. if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
  549. fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
  550. return -1;
  551. }
  552. subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
  553. subrta->rta_type = type;
  554. subrta->rta_len = len;
  555. memcpy(RTA_DATA(subrta), data, alen);
  556. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
  557. return 0;
  558. }
  559. int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
  560. {
  561. memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
  562. while (RTA_OK(rta, len)) {
  563. if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
  564. tb[rta->rta_type] = rta;
  565. rta = RTA_NEXT(rta,len);
  566. }
  567. if (len)
  568. fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  569. return 0;
  570. }
  571. int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
  572. {
  573. int i = 0;
  574. memset(tb, 0, sizeof(struct rtattr *) * max);
  575. while (RTA_OK(rta, len)) {
  576. if (rta->rta_type <= max && i < max)
  577. tb[i++] = rta;
  578. rta = RTA_NEXT(rta,len);
  579. }
  580. if (len)
  581. fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  582. return i;
  583. }
  584. int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
  585. int len)
  586. {
  587. if (RTA_PAYLOAD(rta) < len)
  588. return -1;
  589. if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
  590. rta = RTA_DATA(rta) + RTA_ALIGN(len);
  591. return parse_rtattr_nested(tb, max, rta);
  592. }
  593. memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
  594. return 0;
  595. }