tsconfig.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/net_tstamp.h>
  3. #include <linux/ptp_clock_kernel.h>
  4. #include "netlink.h"
  5. #include "common.h"
  6. #include "bitset.h"
  7. #include "../core/dev.h"
  8. #include "ts.h"
  9. struct tsconfig_req_info {
  10. struct ethnl_req_info base;
  11. };
  12. struct tsconfig_reply_data {
  13. struct ethnl_reply_data base;
  14. struct hwtstamp_provider_desc hwprov_desc;
  15. struct {
  16. u32 tx_type;
  17. u32 rx_filter;
  18. u32 flags;
  19. } hwtst_config;
  20. };
  21. #define TSCONFIG_REPDATA(__reply_base) \
  22. container_of(__reply_base, struct tsconfig_reply_data, base)
  23. const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1] = {
  24. [ETHTOOL_A_TSCONFIG_HEADER] =
  25. NLA_POLICY_NESTED(ethnl_header_policy),
  26. };
  27. static int tsconfig_prepare_data(const struct ethnl_req_info *req_base,
  28. struct ethnl_reply_data *reply_base,
  29. const struct genl_info *info)
  30. {
  31. struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
  32. struct hwtstamp_provider *hwprov = NULL;
  33. struct net_device *dev = reply_base->dev;
  34. struct kernel_hwtstamp_config cfg = {};
  35. int ret;
  36. if (!dev->netdev_ops->ndo_hwtstamp_get)
  37. return -EOPNOTSUPP;
  38. ret = ethnl_ops_begin(dev);
  39. if (ret < 0)
  40. return ret;
  41. ret = dev_get_hwtstamp_phylib(dev, &cfg);
  42. if (ret)
  43. goto out;
  44. data->hwtst_config.tx_type = BIT(cfg.tx_type);
  45. data->hwtst_config.rx_filter = BIT(cfg.rx_filter);
  46. data->hwtst_config.flags = cfg.flags;
  47. data->hwprov_desc.index = -1;
  48. hwprov = rtnl_dereference(dev->hwprov);
  49. if (hwprov) {
  50. data->hwprov_desc.index = hwprov->desc.index;
  51. data->hwprov_desc.qualifier = hwprov->desc.qualifier;
  52. } else {
  53. struct kernel_ethtool_ts_info ts_info = {};
  54. ts_info.phc_index = -1;
  55. ret = __ethtool_get_ts_info(dev, &ts_info);
  56. if (ret)
  57. goto out;
  58. if (ts_info.phc_index == -1)
  59. return -ENODEV;
  60. data->hwprov_desc.index = ts_info.phc_index;
  61. data->hwprov_desc.qualifier = ts_info.phc_qualifier;
  62. }
  63. out:
  64. ethnl_ops_complete(dev);
  65. return ret;
  66. }
  67. static int tsconfig_reply_size(const struct ethnl_req_info *req_base,
  68. const struct ethnl_reply_data *reply_base)
  69. {
  70. const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
  71. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  72. int len = 0;
  73. int ret;
  74. BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32);
  75. BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32);
  76. BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
  77. if (data->hwtst_config.flags) {
  78. ret = ethnl_bitset32_size(&data->hwtst_config.flags,
  79. NULL, __HWTSTAMP_FLAG_CNT,
  80. ts_flags_names, compact);
  81. if (ret < 0)
  82. return ret;
  83. len += ret; /* _TSCONFIG_HWTSTAMP_FLAGS */
  84. }
  85. if (data->hwtst_config.tx_type) {
  86. ret = ethnl_bitset32_size(&data->hwtst_config.tx_type,
  87. NULL, __HWTSTAMP_TX_CNT,
  88. ts_tx_type_names, compact);
  89. if (ret < 0)
  90. return ret;
  91. len += ret; /* _TSCONFIG_TX_TYPES */
  92. }
  93. if (data->hwtst_config.rx_filter) {
  94. ret = ethnl_bitset32_size(&data->hwtst_config.rx_filter,
  95. NULL, __HWTSTAMP_FILTER_CNT,
  96. ts_rx_filter_names, compact);
  97. if (ret < 0)
  98. return ret;
  99. len += ret; /* _TSCONFIG_RX_FILTERS */
  100. }
  101. if (data->hwprov_desc.index >= 0)
  102. /* _TSCONFIG_HWTSTAMP_PROVIDER */
  103. len += nla_total_size(0) +
  104. 2 * nla_total_size(sizeof(u32));
  105. return len;
  106. }
  107. static int tsconfig_fill_reply(struct sk_buff *skb,
  108. const struct ethnl_req_info *req_base,
  109. const struct ethnl_reply_data *reply_base)
  110. {
  111. const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
  112. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  113. int ret;
  114. if (data->hwtst_config.flags) {
  115. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
  116. &data->hwtst_config.flags, NULL,
  117. __HWTSTAMP_FLAG_CNT,
  118. ts_flags_names, compact);
  119. if (ret < 0)
  120. return ret;
  121. }
  122. if (data->hwtst_config.tx_type) {
  123. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_TX_TYPES,
  124. &data->hwtst_config.tx_type, NULL,
  125. __HWTSTAMP_TX_CNT,
  126. ts_tx_type_names, compact);
  127. if (ret < 0)
  128. return ret;
  129. }
  130. if (data->hwtst_config.rx_filter) {
  131. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_RX_FILTERS,
  132. &data->hwtst_config.rx_filter,
  133. NULL, __HWTSTAMP_FILTER_CNT,
  134. ts_rx_filter_names, compact);
  135. if (ret < 0)
  136. return ret;
  137. }
  138. if (data->hwprov_desc.index >= 0) {
  139. struct nlattr *nest;
  140. nest = nla_nest_start(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER);
  141. if (!nest)
  142. return -EMSGSIZE;
  143. if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
  144. data->hwprov_desc.index) ||
  145. nla_put_u32(skb,
  146. ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
  147. data->hwprov_desc.qualifier)) {
  148. nla_nest_cancel(skb, nest);
  149. return -EMSGSIZE;
  150. }
  151. nla_nest_end(skb, nest);
  152. }
  153. return 0;
  154. }
  155. /* TSCONFIG_SET */
  156. const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1] = {
  157. [ETHTOOL_A_TSCONFIG_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
  158. [ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER] =
  159. NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy),
  160. [ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS] = { .type = NLA_NESTED },
  161. [ETHTOOL_A_TSCONFIG_RX_FILTERS] = { .type = NLA_NESTED },
  162. [ETHTOOL_A_TSCONFIG_TX_TYPES] = { .type = NLA_NESTED },
  163. };
  164. static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info)
  165. {
  166. struct tsconfig_reply_data *reply_data;
  167. struct tsconfig_req_info *req_info;
  168. struct sk_buff *rskb;
  169. void *reply_payload;
  170. int reply_len = 0;
  171. int ret;
  172. req_info = kzalloc_obj(*req_info);
  173. if (!req_info)
  174. return -ENOMEM;
  175. reply_data = kmalloc_obj(*reply_data);
  176. if (!reply_data) {
  177. kfree(req_info);
  178. return -ENOMEM;
  179. }
  180. ASSERT_RTNL();
  181. reply_data->base.dev = dev;
  182. ret = tsconfig_prepare_data(&req_info->base, &reply_data->base, info);
  183. if (ret < 0)
  184. goto err_cleanup;
  185. ret = tsconfig_reply_size(&req_info->base, &reply_data->base);
  186. if (ret < 0)
  187. goto err_cleanup;
  188. reply_len = ret + ethnl_reply_header_size();
  189. rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY,
  190. ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload);
  191. if (!rskb)
  192. goto err_cleanup;
  193. ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base);
  194. if (ret < 0)
  195. goto err_cleanup;
  196. genlmsg_end(rskb, reply_payload);
  197. ret = genlmsg_reply(rskb, info);
  198. err_cleanup:
  199. kfree(reply_data);
  200. kfree(req_info);
  201. return ret;
  202. }
  203. static int ethnl_set_tsconfig_validate(struct ethnl_req_info *req_base,
  204. struct genl_info *info)
  205. {
  206. const struct net_device_ops *ops = req_base->dev->netdev_ops;
  207. if (!ops->ndo_hwtstamp_set || !ops->ndo_hwtstamp_get)
  208. return -EOPNOTSUPP;
  209. return 1;
  210. }
  211. static struct hwtstamp_provider *
  212. tsconfig_set_hwprov_from_desc(struct net_device *dev,
  213. struct genl_info *info,
  214. struct hwtstamp_provider_desc *hwprov_desc)
  215. {
  216. struct kernel_ethtool_ts_info ts_info;
  217. struct hwtstamp_provider *hwprov;
  218. struct nlattr **tb = info->attrs;
  219. struct phy_device *phy = NULL;
  220. enum hwtstamp_source source;
  221. int ret;
  222. ret = ethtool_net_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
  223. if (!ret) {
  224. /* Found */
  225. source = HWTSTAMP_SOURCE_NETDEV;
  226. } else {
  227. phy = ethtool_phy_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
  228. if (IS_ERR(phy)) {
  229. if (PTR_ERR(phy) == -ENODEV)
  230. NL_SET_ERR_MSG_ATTR(info->extack,
  231. tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
  232. "phc not in this net device topology");
  233. return ERR_CAST(phy);
  234. }
  235. source = HWTSTAMP_SOURCE_PHYLIB;
  236. }
  237. hwprov = kzalloc_obj(*hwprov);
  238. if (!hwprov)
  239. return ERR_PTR(-ENOMEM);
  240. hwprov->desc.index = hwprov_desc->index;
  241. hwprov->desc.qualifier = hwprov_desc->qualifier;
  242. hwprov->source = source;
  243. hwprov->phydev = phy;
  244. return hwprov;
  245. }
  246. static int ethnl_set_tsconfig(struct ethnl_req_info *req_base,
  247. struct genl_info *info)
  248. {
  249. struct kernel_hwtstamp_config hwtst_config = {0};
  250. bool hwprov_mod = false, config_mod = false;
  251. struct hwtstamp_provider *hwprov = NULL;
  252. struct net_device *dev = req_base->dev;
  253. struct nlattr **tb = info->attrs;
  254. int ret;
  255. BUILD_BUG_ON(__HWTSTAMP_TX_CNT >= 32);
  256. BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT >= 32);
  257. BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
  258. if (!netif_device_present(dev))
  259. return -ENODEV;
  260. if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]) {
  261. struct hwtstamp_provider_desc __hwprov_desc = {.index = -1};
  262. struct hwtstamp_provider *__hwprov;
  263. __hwprov = rtnl_dereference(dev->hwprov);
  264. if (__hwprov) {
  265. __hwprov_desc.index = __hwprov->desc.index;
  266. __hwprov_desc.qualifier = __hwprov->desc.qualifier;
  267. }
  268. ret = ts_parse_hwtst_provider(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
  269. &__hwprov_desc, info->extack,
  270. &hwprov_mod);
  271. if (ret < 0)
  272. return ret;
  273. if (hwprov_mod) {
  274. hwprov = tsconfig_set_hwprov_from_desc(dev, info,
  275. &__hwprov_desc);
  276. if (IS_ERR(hwprov))
  277. return PTR_ERR(hwprov);
  278. }
  279. }
  280. /* Get current hwtstamp config if we are not changing the
  281. * hwtstamp source. It will be zeroed in the other case.
  282. */
  283. if (!hwprov_mod) {
  284. ret = dev_get_hwtstamp_phylib(dev, &hwtst_config);
  285. if (ret < 0 && ret != -EOPNOTSUPP)
  286. goto err_free_hwprov;
  287. }
  288. /* Get the hwtstamp config from netlink */
  289. if (tb[ETHTOOL_A_TSCONFIG_TX_TYPES]) {
  290. u32 req_tx_type;
  291. req_tx_type = BIT(hwtst_config.tx_type);
  292. ret = ethnl_update_bitset32(&req_tx_type,
  293. __HWTSTAMP_TX_CNT,
  294. tb[ETHTOOL_A_TSCONFIG_TX_TYPES],
  295. ts_tx_type_names, info->extack,
  296. &config_mod);
  297. if (ret < 0)
  298. goto err_free_hwprov;
  299. /* Select only one tx type at a time */
  300. if (ffs(req_tx_type) != fls(req_tx_type)) {
  301. ret = -EINVAL;
  302. goto err_free_hwprov;
  303. }
  304. hwtst_config.tx_type = ffs(req_tx_type) - 1;
  305. }
  306. if (tb[ETHTOOL_A_TSCONFIG_RX_FILTERS]) {
  307. u32 req_rx_filter;
  308. req_rx_filter = BIT(hwtst_config.rx_filter);
  309. ret = ethnl_update_bitset32(&req_rx_filter,
  310. __HWTSTAMP_FILTER_CNT,
  311. tb[ETHTOOL_A_TSCONFIG_RX_FILTERS],
  312. ts_rx_filter_names, info->extack,
  313. &config_mod);
  314. if (ret < 0)
  315. goto err_free_hwprov;
  316. /* Select only one rx filter at a time */
  317. if (ffs(req_rx_filter) != fls(req_rx_filter)) {
  318. ret = -EINVAL;
  319. goto err_free_hwprov;
  320. }
  321. hwtst_config.rx_filter = ffs(req_rx_filter) - 1;
  322. }
  323. if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS]) {
  324. ret = ethnl_update_bitset32(&hwtst_config.flags,
  325. __HWTSTAMP_FLAG_CNT,
  326. tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS],
  327. ts_flags_names, info->extack,
  328. &config_mod);
  329. if (ret < 0)
  330. goto err_free_hwprov;
  331. }
  332. ret = net_hwtstamp_validate(&hwtst_config);
  333. if (ret)
  334. goto err_free_hwprov;
  335. if (hwprov_mod) {
  336. struct kernel_hwtstamp_config zero_config = {0};
  337. struct hwtstamp_provider *__hwprov;
  338. /* Disable current time stamping if we try to enable
  339. * another one
  340. */
  341. ret = dev_set_hwtstamp_phylib(dev, &zero_config, info->extack);
  342. if (ret < 0)
  343. goto err_free_hwprov;
  344. /* Change the selected hwtstamp source */
  345. __hwprov = rcu_replace_pointer_rtnl(dev->hwprov, hwprov);
  346. if (__hwprov)
  347. kfree_rcu(__hwprov, rcu_head);
  348. }
  349. if (config_mod) {
  350. ret = dev_set_hwtstamp_phylib(dev, &hwtst_config,
  351. info->extack);
  352. if (ret < 0)
  353. return ret;
  354. }
  355. ret = tsconfig_send_reply(dev, info);
  356. if (ret && ret != -EOPNOTSUPP) {
  357. NL_SET_ERR_MSG(info->extack,
  358. "error while reading the new configuration set");
  359. return ret;
  360. }
  361. /* tsconfig has no notification */
  362. return 0;
  363. err_free_hwprov:
  364. kfree(hwprov);
  365. return ret;
  366. }
  367. const struct ethnl_request_ops ethnl_tsconfig_request_ops = {
  368. .request_cmd = ETHTOOL_MSG_TSCONFIG_GET,
  369. .reply_cmd = ETHTOOL_MSG_TSCONFIG_GET_REPLY,
  370. .hdr_attr = ETHTOOL_A_TSCONFIG_HEADER,
  371. .req_info_size = sizeof(struct tsconfig_req_info),
  372. .reply_data_size = sizeof(struct tsconfig_reply_data),
  373. .prepare_data = tsconfig_prepare_data,
  374. .reply_size = tsconfig_reply_size,
  375. .fill_reply = tsconfig_fill_reply,
  376. .set_validate = ethnl_set_tsconfig_validate,
  377. .set = ethnl_set_tsconfig,
  378. };