use-rtnetlink.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /* RTNETLINK client
  2. *
  3. * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/netlink.h>
  12. #include <linux/rtnetlink.h>
  13. #include <linux/if_addr.h>
  14. #include <linux/if_arp.h>
  15. #include <linux/inetdevice.h>
  16. #include <net/netlink.h>
  17. #include "internal.h"
  18. struct afs_rtm_desc {
  19. struct socket *nlsock;
  20. struct afs_interface *bufs;
  21. u8 *mac;
  22. size_t nbufs;
  23. size_t maxbufs;
  24. void *data;
  25. ssize_t datalen;
  26. size_t datamax;
  27. int msg_seq;
  28. unsigned mac_index;
  29. bool wantloopback;
  30. int (*parse)(struct afs_rtm_desc *, struct nlmsghdr *);
  31. };
  32. /*
  33. * parse an RTM_GETADDR response
  34. */
  35. static int afs_rtm_getaddr_parse(struct afs_rtm_desc *desc,
  36. struct nlmsghdr *nlhdr)
  37. {
  38. struct afs_interface *this;
  39. struct ifaddrmsg *ifa;
  40. struct rtattr *rtattr;
  41. const char *name;
  42. size_t len;
  43. ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
  44. _enter("{ix=%d,af=%d}", ifa->ifa_index, ifa->ifa_family);
  45. if (ifa->ifa_family != AF_INET) {
  46. _leave(" = 0 [family %d]", ifa->ifa_family);
  47. return 0;
  48. }
  49. if (desc->nbufs >= desc->maxbufs) {
  50. _leave(" = 0 [max %zu/%zu]", desc->nbufs, desc->maxbufs);
  51. return 0;
  52. }
  53. this = &desc->bufs[desc->nbufs];
  54. this->index = ifa->ifa_index;
  55. this->netmask.s_addr = inet_make_mask(ifa->ifa_prefixlen);
  56. this->mtu = 0;
  57. rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifaddrmsg));
  58. len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifaddrmsg));
  59. name = "unknown";
  60. for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
  61. switch (rtattr->rta_type) {
  62. case IFA_ADDRESS:
  63. memcpy(&this->address, RTA_DATA(rtattr), 4);
  64. break;
  65. case IFA_LABEL:
  66. name = RTA_DATA(rtattr);
  67. break;
  68. }
  69. }
  70. _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT,
  71. name, NIPQUAD(this->address), NIPQUAD(this->netmask));
  72. desc->nbufs++;
  73. _leave(" = 0");
  74. return 0;
  75. }
  76. /*
  77. * parse an RTM_GETLINK response for MTUs
  78. */
  79. static int afs_rtm_getlink_if_parse(struct afs_rtm_desc *desc,
  80. struct nlmsghdr *nlhdr)
  81. {
  82. struct afs_interface *this;
  83. struct ifinfomsg *ifi;
  84. struct rtattr *rtattr;
  85. const char *name;
  86. size_t len, loop;
  87. ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
  88. _enter("{ix=%d}", ifi->ifi_index);
  89. for (loop = 0; loop < desc->nbufs; loop++) {
  90. this = &desc->bufs[loop];
  91. if (this->index == ifi->ifi_index)
  92. goto found;
  93. }
  94. _leave(" = 0 [no match]");
  95. return 0;
  96. found:
  97. if (ifi->ifi_type == ARPHRD_LOOPBACK && !desc->wantloopback) {
  98. _leave(" = 0 [loopback]");
  99. return 0;
  100. }
  101. rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
  102. len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
  103. name = "unknown";
  104. for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
  105. switch (rtattr->rta_type) {
  106. case IFLA_MTU:
  107. memcpy(&this->mtu, RTA_DATA(rtattr), 4);
  108. break;
  109. case IFLA_IFNAME:
  110. name = RTA_DATA(rtattr);
  111. break;
  112. }
  113. }
  114. _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
  115. name, NIPQUAD(this->address), NIPQUAD(this->netmask),
  116. this->mtu);
  117. _leave(" = 0");
  118. return 0;
  119. }
  120. /*
  121. * parse an RTM_GETLINK response for the MAC address belonging to the lowest
  122. * non-internal interface
  123. */
  124. static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc *desc,
  125. struct nlmsghdr *nlhdr)
  126. {
  127. struct ifinfomsg *ifi;
  128. struct rtattr *rtattr;
  129. const char *name;
  130. size_t remain, len;
  131. bool set;
  132. ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
  133. _enter("{ix=%d}", ifi->ifi_index);
  134. if (ifi->ifi_index >= desc->mac_index) {
  135. _leave(" = 0 [high]");
  136. return 0;
  137. }
  138. if (ifi->ifi_type == ARPHRD_LOOPBACK) {
  139. _leave(" = 0 [loopback]");
  140. return 0;
  141. }
  142. rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
  143. remain = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
  144. name = "unknown";
  145. set = false;
  146. for (; RTA_OK(rtattr, remain); rtattr = RTA_NEXT(rtattr, remain)) {
  147. switch (rtattr->rta_type) {
  148. case IFLA_ADDRESS:
  149. len = RTA_PAYLOAD(rtattr);
  150. memcpy(desc->mac, RTA_DATA(rtattr),
  151. min_t(size_t, len, 6));
  152. desc->mac_index = ifi->ifi_index;
  153. set = true;
  154. break;
  155. case IFLA_IFNAME:
  156. name = RTA_DATA(rtattr);
  157. break;
  158. }
  159. }
  160. if (set)
  161. _debug("%s: %02x:%02x:%02x:%02x:%02x:%02x",
  162. name,
  163. desc->mac[0], desc->mac[1], desc->mac[2],
  164. desc->mac[3], desc->mac[4], desc->mac[5]);
  165. _leave(" = 0");
  166. return 0;
  167. }
  168. /*
  169. * read the rtnetlink response and pass to parsing routine
  170. */
  171. static int afs_read_rtm(struct afs_rtm_desc *desc)
  172. {
  173. struct nlmsghdr *nlhdr, tmphdr;
  174. struct msghdr msg;
  175. struct kvec iov[1];
  176. void *data;
  177. bool last = false;
  178. int len, ret, remain;
  179. _enter("");
  180. do {
  181. /* first of all peek to see how big the packet is */
  182. memset(&msg, 0, sizeof(msg));
  183. iov[0].iov_base = &tmphdr;
  184. iov[0].iov_len = sizeof(tmphdr);
  185. len = kernel_recvmsg(desc->nlsock, &msg, iov, 1,
  186. sizeof(tmphdr), MSG_PEEK | MSG_TRUNC);
  187. if (len < 0) {
  188. _leave(" = %d [peek]", len);
  189. return len;
  190. }
  191. if (len == 0)
  192. continue;
  193. if (len < sizeof(tmphdr) || len < NLMSG_PAYLOAD(&tmphdr, 0)) {
  194. _leave(" = -EMSGSIZE");
  195. return -EMSGSIZE;
  196. }
  197. if (desc->datamax < len) {
  198. kfree(desc->data);
  199. desc->data = NULL;
  200. data = kmalloc(len, GFP_KERNEL);
  201. if (!data)
  202. return -ENOMEM;
  203. desc->data = data;
  204. }
  205. desc->datamax = len;
  206. /* read all the data from this packet */
  207. iov[0].iov_base = desc->data;
  208. iov[0].iov_len = desc->datamax;
  209. desc->datalen = kernel_recvmsg(desc->nlsock, &msg, iov, 1,
  210. desc->datamax, 0);
  211. if (desc->datalen < 0) {
  212. _leave(" = %zd [recv]", desc->datalen);
  213. return desc->datalen;
  214. }
  215. nlhdr = desc->data;
  216. /* check if the header is valid */
  217. if (!NLMSG_OK(nlhdr, desc->datalen) ||
  218. nlhdr->nlmsg_type == NLMSG_ERROR) {
  219. _leave(" = -EIO");
  220. return -EIO;
  221. }
  222. /* see if this is the last message */
  223. if (nlhdr->nlmsg_type == NLMSG_DONE ||
  224. !(nlhdr->nlmsg_flags & NLM_F_MULTI))
  225. last = true;
  226. /* parse the bits we got this time */
  227. nlmsg_for_each_msg(nlhdr, desc->data, desc->datalen, remain) {
  228. ret = desc->parse(desc, nlhdr);
  229. if (ret < 0) {
  230. _leave(" = %d [parse]", ret);
  231. return ret;
  232. }
  233. }
  234. } while (!last);
  235. _leave(" = 0");
  236. return 0;
  237. }
  238. /*
  239. * list the interface bound addresses to get the address and netmask
  240. */
  241. static int afs_rtm_getaddr(struct afs_rtm_desc *desc)
  242. {
  243. struct msghdr msg;
  244. struct kvec iov[1];
  245. int ret;
  246. struct {
  247. struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
  248. struct ifaddrmsg addr_msg __attribute__((aligned(NLMSG_ALIGNTO)));
  249. } request;
  250. _enter("");
  251. memset(&request, 0, sizeof(request));
  252. request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
  253. request.nl_msg.nlmsg_type = RTM_GETADDR;
  254. request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  255. request.nl_msg.nlmsg_seq = desc->msg_seq++;
  256. request.nl_msg.nlmsg_pid = 0;
  257. memset(&msg, 0, sizeof(msg));
  258. iov[0].iov_base = &request;
  259. iov[0].iov_len = sizeof(request);
  260. ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
  261. _leave(" = %d", ret);
  262. return ret;
  263. }
  264. /*
  265. * list the interface link statuses to get the MTUs
  266. */
  267. static int afs_rtm_getlink(struct afs_rtm_desc *desc)
  268. {
  269. struct msghdr msg;
  270. struct kvec iov[1];
  271. int ret;
  272. struct {
  273. struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
  274. struct ifinfomsg link_msg __attribute__((aligned(NLMSG_ALIGNTO)));
  275. } request;
  276. _enter("");
  277. memset(&request, 0, sizeof(request));
  278. request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  279. request.nl_msg.nlmsg_type = RTM_GETLINK;
  280. request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
  281. request.nl_msg.nlmsg_seq = desc->msg_seq++;
  282. request.nl_msg.nlmsg_pid = 0;
  283. memset(&msg, 0, sizeof(msg));
  284. iov[0].iov_base = &request;
  285. iov[0].iov_len = sizeof(request);
  286. ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
  287. _leave(" = %d", ret);
  288. return ret;
  289. }
  290. /*
  291. * cull any interface records for which there isn't an MTU value
  292. */
  293. static void afs_cull_interfaces(struct afs_rtm_desc *desc)
  294. {
  295. struct afs_interface *bufs = desc->bufs;
  296. size_t nbufs = desc->nbufs;
  297. int loop, point = 0;
  298. _enter("{%zu}", nbufs);
  299. for (loop = 0; loop < nbufs; loop++) {
  300. if (desc->bufs[loop].mtu != 0) {
  301. if (loop != point) {
  302. ASSERTCMP(loop, >, point);
  303. bufs[point] = bufs[loop];
  304. }
  305. point++;
  306. }
  307. }
  308. desc->nbufs = point;
  309. _leave(" [%zu/%zu]", desc->nbufs, nbufs);
  310. }
  311. /*
  312. * get a list of this system's interface IPv4 addresses, netmasks and MTUs
  313. * - returns the number of interface records in the buffer
  314. */
  315. int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
  316. bool wantloopback)
  317. {
  318. struct afs_rtm_desc desc;
  319. int ret, loop;
  320. _enter("");
  321. memset(&desc, 0, sizeof(desc));
  322. desc.bufs = bufs;
  323. desc.maxbufs = maxbufs;
  324. desc.wantloopback = wantloopback;
  325. ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
  326. &desc.nlsock);
  327. if (ret < 0) {
  328. _leave(" = %d [sock]", ret);
  329. return ret;
  330. }
  331. /* issue RTM_GETADDR */
  332. desc.parse = afs_rtm_getaddr_parse;
  333. ret = afs_rtm_getaddr(&desc);
  334. if (ret < 0)
  335. goto error;
  336. ret = afs_read_rtm(&desc);
  337. if (ret < 0)
  338. goto error;
  339. /* issue RTM_GETLINK */
  340. desc.parse = afs_rtm_getlink_if_parse;
  341. ret = afs_rtm_getlink(&desc);
  342. if (ret < 0)
  343. goto error;
  344. ret = afs_read_rtm(&desc);
  345. if (ret < 0)
  346. goto error;
  347. afs_cull_interfaces(&desc);
  348. ret = desc.nbufs;
  349. for (loop = 0; loop < ret; loop++)
  350. _debug("[%d] "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
  351. bufs[loop].index,
  352. NIPQUAD(bufs[loop].address),
  353. NIPQUAD(bufs[loop].netmask),
  354. bufs[loop].mtu);
  355. error:
  356. kfree(desc.data);
  357. sock_release(desc.nlsock);
  358. _leave(" = %d", ret);
  359. return ret;
  360. }
  361. /*
  362. * get a MAC address from a random ethernet interface that has a real one
  363. * - the buffer should be 6 bytes in size
  364. */
  365. int afs_get_MAC_address(u8 mac[6])
  366. {
  367. struct afs_rtm_desc desc;
  368. int ret;
  369. _enter("");
  370. memset(&desc, 0, sizeof(desc));
  371. desc.mac = mac;
  372. desc.mac_index = UINT_MAX;
  373. ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
  374. &desc.nlsock);
  375. if (ret < 0) {
  376. _leave(" = %d [sock]", ret);
  377. return ret;
  378. }
  379. /* issue RTM_GETLINK */
  380. desc.parse = afs_rtm_getlink_mac_parse;
  381. ret = afs_rtm_getlink(&desc);
  382. if (ret < 0)
  383. goto error;
  384. ret = afs_read_rtm(&desc);
  385. if (ret < 0)
  386. goto error;
  387. if (desc.mac_index < UINT_MAX) {
  388. /* got a MAC address */
  389. _debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x",
  390. desc.mac_index,
  391. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  392. } else {
  393. ret = -ENONET;
  394. }
  395. error:
  396. sock_release(desc.nlsock);
  397. _leave(" = %d", ret);
  398. return ret;
  399. }