inet.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * lib/route/link/inet.c AF_INET link operations
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup link_API
  13. * @defgroup link_inet IPv4 Link Module
  14. * @brief Implementation of IPv4 specific link attributes
  15. *
  16. *
  17. *
  18. * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
  19. * @code
  20. * struct nl_cache *cache;
  21. * struct rtnl_link *link;
  22. * uint32_t value;
  23. *
  24. * // Allocate a link cache
  25. * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
  26. *
  27. * // Search for the link we wish to see the value from
  28. * link = rtnl_link_get_by_name(cache, "eth0");
  29. *
  30. * // Read the value of the setting IPV4_DEVCONF_FORWARDING
  31. * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
  32. * // Error: Unable to read config setting
  33. *
  34. * printf("forwarding is %s\n", value ? "enabled" : "disabled");
  35. * @endcode
  36. *
  37. * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
  38. * @code
  39. * //
  40. * // ... Continueing from the previous example ...
  41. * //
  42. *
  43. * struct rtnl_link *new;
  44. *
  45. * // Allocate a new link to store the changes we wish to make.
  46. * new = rtnl_link_alloc();
  47. *
  48. * // Set IPV4_DEVCONF_FORWARDING to '1'
  49. * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
  50. *
  51. * // Send the change request to the kernel.
  52. * rtnl_link_change(sock, link, new, 0);
  53. * @endcode
  54. *
  55. * @{
  56. */
  57. #include <netlink-private/netlink.h>
  58. #include <netlink/netlink.h>
  59. #include <netlink/attr.h>
  60. #include <netlink/route/rtnl.h>
  61. #include <netlink-private/route/link/api.h>
  62. /** @cond SKIP */
  63. struct inet_data
  64. {
  65. uint8_t i_confset[IPV4_DEVCONF_MAX];
  66. uint32_t i_conf[IPV4_DEVCONF_MAX];
  67. };
  68. /** @endcond */
  69. static void *inet_alloc(struct rtnl_link *link)
  70. {
  71. return calloc(1, sizeof(struct inet_data));
  72. }
  73. static void *inet_clone(struct rtnl_link *link, void *data)
  74. {
  75. struct inet_data *id;
  76. if ((id = inet_alloc(link)))
  77. memcpy(id, data, sizeof(*id));
  78. return id;
  79. }
  80. static void inet_free(struct rtnl_link *link, void *data)
  81. {
  82. free(data);
  83. }
  84. static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = {
  85. [IFLA_INET_CONF] = { .minlen = 4 },
  86. };
  87. static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
  88. {
  89. struct inet_data *id = data;
  90. struct nlattr *tb[IFLA_INET_MAX+1];
  91. int err;
  92. err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
  93. if (err < 0)
  94. return err;
  95. if (tb[IFLA_INET_CONF] && nla_len(tb[IFLA_INET_CONF]) % 4)
  96. return -EINVAL;
  97. if (tb[IFLA_INET_CONF]) {
  98. int i;
  99. int len = min_t(int, IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4);
  100. for (i = 0; i < len; i++)
  101. id->i_confset[i] = 1;
  102. nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
  103. }
  104. return 0;
  105. }
  106. static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
  107. {
  108. struct inet_data *id = data;
  109. struct nlattr *nla;
  110. int i;
  111. if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
  112. return -NLE_MSGSIZE;
  113. for (i = 0; i < IPV4_DEVCONF_MAX; i++)
  114. if (id->i_confset[i])
  115. NLA_PUT_U32(msg, i+1, id->i_conf[i]);
  116. nla_nest_end(msg, nla);
  117. return 0;
  118. nla_put_failure:
  119. return -NLE_MSGSIZE;
  120. }
  121. static const struct trans_tbl inet_devconf[] = {
  122. __ADD(IPV4_DEVCONF_FORWARDING, forwarding)
  123. __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding)
  124. __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp)
  125. __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
  126. __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects)
  127. __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects)
  128. __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media)
  129. __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter)
  130. __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
  131. __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay)
  132. __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians)
  133. __ADD(IPV4_DEVCONF_TAG, tag)
  134. __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter)
  135. __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id)
  136. __ADD(IPV4_DEVCONF_NOXFRM, noxfrm)
  137. __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy)
  138. __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version)
  139. __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce)
  140. __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore)
  141. __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries)
  142. __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept)
  143. __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify)
  144. __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local)
  145. __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark)
  146. __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan)
  147. __ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet)
  148. __ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval)
  149. __ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval)
  150. };
  151. const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
  152. {
  153. return __type2str(type, buf, len, inet_devconf,
  154. ARRAY_SIZE(inet_devconf));
  155. }
  156. int rtnl_link_inet_str2devconf(const char *name)
  157. {
  158. return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
  159. }
  160. static void inet_dump_details(struct rtnl_link *link,
  161. struct nl_dump_params *p, void *data)
  162. {
  163. struct inet_data *id = data;
  164. char buf[64];
  165. int i, n = 0;
  166. nl_dump_line(p, " ipv4 devconf:\n");
  167. nl_dump_line(p, " ");
  168. for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
  169. nl_dump_line(p, "%-19s %3u",
  170. rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
  171. id->i_confset[i] ? id->i_conf[i] : 0);
  172. if (++n == 3) {
  173. nl_dump(p, "\n");
  174. nl_dump_line(p, " ");
  175. n = 0;
  176. } else
  177. nl_dump(p, " ");
  178. }
  179. if (n != 0)
  180. nl_dump(p, "\n");
  181. }
  182. static struct rtnl_link_af_ops inet_ops = {
  183. .ao_family = AF_INET,
  184. .ao_alloc = &inet_alloc,
  185. .ao_clone = &inet_clone,
  186. .ao_free = &inet_free,
  187. .ao_parse_af = &inet_parse_af,
  188. .ao_fill_af = &inet_fill_af,
  189. .ao_dump[NL_DUMP_DETAILS] = &inet_dump_details,
  190. };
  191. /**
  192. * Get value of a ipv4 link configuration setting
  193. * @arg link Link object
  194. * @arg cfgid Configuration identifier
  195. * @arg res Result pointer
  196. *
  197. * Stores the value of the specified configuration setting in the provided
  198. * result pointer.
  199. *
  200. * @return 0 on success or a negative error code.
  201. * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
  202. * @return -NLE_NOATTR configuration setting not available
  203. * @return -NLE_INVAL cfgid not set. If the link was received via netlink,
  204. * it means that the cfgid is not supported.
  205. */
  206. int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
  207. uint32_t *res)
  208. {
  209. struct inet_data *id;
  210. if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
  211. return -NLE_RANGE;
  212. if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
  213. return -NLE_NOATTR;
  214. if (!id->i_confset[cfgid - 1])
  215. return -NLE_INVAL;
  216. *res = id->i_conf[cfgid - 1];
  217. return 0;
  218. }
  219. /**
  220. * Change value of a ipv4 link configuration setting
  221. * @arg link Link object
  222. * @arg cfgid Configuration identifier
  223. * @arg value New value
  224. *
  225. * Changes the value in the per link ipv4 configuration array.
  226. *
  227. * @return 0 on success or a negative error code.
  228. * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
  229. * @return -NLE_NOMEM memory allocation failed
  230. */
  231. int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
  232. uint32_t value)
  233. {
  234. struct inet_data *id;
  235. if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
  236. return -NLE_NOMEM;
  237. if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
  238. return -NLE_RANGE;
  239. id->i_confset[cfgid - 1] = 1;
  240. id->i_conf[cfgid - 1] = value;
  241. return 0;
  242. }
  243. static void __init inet_init(void)
  244. {
  245. rtnl_link_af_register(&inet_ops);
  246. }
  247. static void __exit inet_exit(void)
  248. {
  249. rtnl_link_af_unregister(&inet_ops);
  250. }
  251. /** @} */