debugfs.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /* This program is free software; you can redistribute it and/or modify
  2. * it under the terms of the GNU General Public License version 2
  3. * as published by the Free Software Foundation.
  4. *
  5. * This program is distributed in the hope that it will be useful,
  6. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. * GNU General Public License for more details.
  9. *
  10. * Authors:
  11. * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
  12. * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
  13. */
  14. #include <net/6lowpan.h>
  15. #include "6lowpan_i.h"
  16. #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8
  17. static struct dentry *lowpan_debugfs;
  18. static int lowpan_ctx_flag_active_set(void *data, u64 val)
  19. {
  20. struct lowpan_iphc_ctx *ctx = data;
  21. if (val != 0 && val != 1)
  22. return -EINVAL;
  23. if (val)
  24. set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
  25. else
  26. clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
  27. return 0;
  28. }
  29. static int lowpan_ctx_flag_active_get(void *data, u64 *val)
  30. {
  31. *val = lowpan_iphc_ctx_is_active(data);
  32. return 0;
  33. }
  34. DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops,
  35. lowpan_ctx_flag_active_get,
  36. lowpan_ctx_flag_active_set, "%llu\n");
  37. static int lowpan_ctx_flag_c_set(void *data, u64 val)
  38. {
  39. struct lowpan_iphc_ctx *ctx = data;
  40. if (val != 0 && val != 1)
  41. return -EINVAL;
  42. if (val)
  43. set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
  44. else
  45. clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
  46. return 0;
  47. }
  48. static int lowpan_ctx_flag_c_get(void *data, u64 *val)
  49. {
  50. *val = lowpan_iphc_ctx_is_compression(data);
  51. return 0;
  52. }
  53. DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
  54. lowpan_ctx_flag_c_set, "%llu\n");
  55. static int lowpan_ctx_plen_set(void *data, u64 val)
  56. {
  57. struct lowpan_iphc_ctx *ctx = data;
  58. struct lowpan_iphc_ctx_table *t =
  59. container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
  60. if (val > 128)
  61. return -EINVAL;
  62. spin_lock_bh(&t->lock);
  63. ctx->plen = val;
  64. spin_unlock_bh(&t->lock);
  65. return 0;
  66. }
  67. static int lowpan_ctx_plen_get(void *data, u64 *val)
  68. {
  69. struct lowpan_iphc_ctx *ctx = data;
  70. struct lowpan_iphc_ctx_table *t =
  71. container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
  72. spin_lock_bh(&t->lock);
  73. *val = ctx->plen;
  74. spin_unlock_bh(&t->lock);
  75. return 0;
  76. }
  77. DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
  78. lowpan_ctx_plen_set, "%llu\n");
  79. static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
  80. {
  81. struct lowpan_iphc_ctx *ctx = file->private;
  82. struct lowpan_iphc_ctx_table *t =
  83. container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
  84. spin_lock_bh(&t->lock);
  85. seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  86. be16_to_cpu(ctx->pfx.s6_addr16[0]),
  87. be16_to_cpu(ctx->pfx.s6_addr16[1]),
  88. be16_to_cpu(ctx->pfx.s6_addr16[2]),
  89. be16_to_cpu(ctx->pfx.s6_addr16[3]),
  90. be16_to_cpu(ctx->pfx.s6_addr16[4]),
  91. be16_to_cpu(ctx->pfx.s6_addr16[5]),
  92. be16_to_cpu(ctx->pfx.s6_addr16[6]),
  93. be16_to_cpu(ctx->pfx.s6_addr16[7]));
  94. spin_unlock_bh(&t->lock);
  95. return 0;
  96. }
  97. static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file)
  98. {
  99. return single_open(file, lowpan_ctx_pfx_show, inode->i_private);
  100. }
  101. static ssize_t lowpan_ctx_pfx_write(struct file *fp,
  102. const char __user *user_buf, size_t count,
  103. loff_t *ppos)
  104. {
  105. char buf[128] = {};
  106. struct seq_file *file = fp->private_data;
  107. struct lowpan_iphc_ctx *ctx = file->private;
  108. struct lowpan_iphc_ctx_table *t =
  109. container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
  110. int status = count, n, i;
  111. unsigned int addr[8];
  112. if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
  113. count))) {
  114. status = -EFAULT;
  115. goto out;
  116. }
  117. n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
  118. &addr[0], &addr[1], &addr[2], &addr[3], &addr[4],
  119. &addr[5], &addr[6], &addr[7]);
  120. if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) {
  121. status = -EINVAL;
  122. goto out;
  123. }
  124. spin_lock_bh(&t->lock);
  125. for (i = 0; i < 8; i++)
  126. ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff);
  127. spin_unlock_bh(&t->lock);
  128. out:
  129. return status;
  130. }
  131. static const struct file_operations lowpan_ctx_pfx_fops = {
  132. .open = lowpan_ctx_pfx_open,
  133. .read = seq_read,
  134. .write = lowpan_ctx_pfx_write,
  135. .llseek = seq_lseek,
  136. .release = single_release,
  137. };
  138. static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
  139. struct dentry *ctx, u8 id)
  140. {
  141. struct lowpan_dev *ldev = lowpan_dev(dev);
  142. struct dentry *dentry, *root;
  143. char buf[32];
  144. WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE);
  145. sprintf(buf, "%d", id);
  146. root = debugfs_create_dir(buf, ctx);
  147. if (!root)
  148. return -EINVAL;
  149. dentry = debugfs_create_file("active", 0644, root,
  150. &ldev->ctx.table[id],
  151. &lowpan_ctx_flag_active_fops);
  152. if (!dentry)
  153. return -EINVAL;
  154. dentry = debugfs_create_file("compression", 0644, root,
  155. &ldev->ctx.table[id],
  156. &lowpan_ctx_flag_c_fops);
  157. if (!dentry)
  158. return -EINVAL;
  159. dentry = debugfs_create_file("prefix", 0644, root,
  160. &ldev->ctx.table[id],
  161. &lowpan_ctx_pfx_fops);
  162. if (!dentry)
  163. return -EINVAL;
  164. dentry = debugfs_create_file("prefix_len", 0644, root,
  165. &ldev->ctx.table[id],
  166. &lowpan_ctx_plen_fops);
  167. if (!dentry)
  168. return -EINVAL;
  169. return 0;
  170. }
  171. static int lowpan_context_show(struct seq_file *file, void *offset)
  172. {
  173. struct lowpan_iphc_ctx_table *t = file->private;
  174. int i;
  175. seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C');
  176. seq_puts(file, "-------------------------------------------------\n");
  177. spin_lock_bh(&t->lock);
  178. for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
  179. if (!lowpan_iphc_ctx_is_active(&t->table[i]))
  180. continue;
  181. seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id,
  182. &t->table[i].pfx, t->table[i].plen,
  183. lowpan_iphc_ctx_is_compression(&t->table[i]));
  184. }
  185. spin_unlock_bh(&t->lock);
  186. return 0;
  187. }
  188. static int lowpan_context_open(struct inode *inode, struct file *file)
  189. {
  190. return single_open(file, lowpan_context_show, inode->i_private);
  191. }
  192. static const struct file_operations lowpan_context_fops = {
  193. .open = lowpan_context_open,
  194. .read = seq_read,
  195. .llseek = seq_lseek,
  196. .release = single_release,
  197. };
  198. static int lowpan_short_addr_get(void *data, u64 *val)
  199. {
  200. struct wpan_dev *wdev = data;
  201. rtnl_lock();
  202. *val = le16_to_cpu(wdev->short_addr);
  203. rtnl_unlock();
  204. return 0;
  205. }
  206. DEFINE_SIMPLE_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get,
  207. NULL, "0x%04llx\n");
  208. static int lowpan_dev_debugfs_802154_init(const struct net_device *dev,
  209. struct lowpan_dev *ldev)
  210. {
  211. struct dentry *dentry, *root;
  212. if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
  213. return 0;
  214. root = debugfs_create_dir("ieee802154", ldev->iface_debugfs);
  215. if (!root)
  216. return -EINVAL;
  217. dentry = debugfs_create_file("short_addr", 0444, root,
  218. lowpan_802154_dev(dev)->wdev->ieee802154_ptr,
  219. &lowpan_short_addr_fops);
  220. if (!dentry)
  221. return -EINVAL;
  222. return 0;
  223. }
  224. int lowpan_dev_debugfs_init(struct net_device *dev)
  225. {
  226. struct lowpan_dev *ldev = lowpan_dev(dev);
  227. struct dentry *contexts, *dentry;
  228. int ret, i;
  229. /* creating the root */
  230. ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
  231. if (!ldev->iface_debugfs)
  232. goto fail;
  233. contexts = debugfs_create_dir("contexts", ldev->iface_debugfs);
  234. if (!contexts)
  235. goto remove_root;
  236. dentry = debugfs_create_file("show", 0644, contexts,
  237. &lowpan_dev(dev)->ctx,
  238. &lowpan_context_fops);
  239. if (!dentry)
  240. goto remove_root;
  241. for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
  242. ret = lowpan_dev_debugfs_ctx_init(dev, contexts, i);
  243. if (ret < 0)
  244. goto remove_root;
  245. }
  246. ret = lowpan_dev_debugfs_802154_init(dev, ldev);
  247. if (ret < 0)
  248. goto remove_root;
  249. return 0;
  250. remove_root:
  251. lowpan_dev_debugfs_exit(dev);
  252. fail:
  253. return -EINVAL;
  254. }
  255. void lowpan_dev_debugfs_exit(struct net_device *dev)
  256. {
  257. debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs);
  258. }
  259. int __init lowpan_debugfs_init(void)
  260. {
  261. lowpan_debugfs = debugfs_create_dir("6lowpan", NULL);
  262. if (!lowpan_debugfs)
  263. return -EINVAL;
  264. return 0;
  265. }
  266. void lowpan_debugfs_exit(void)
  267. {
  268. debugfs_remove_recursive(lowpan_debugfs);
  269. }