1b1815fd9SAlexander Aring /* This program is free software; you can redistribute it and/or modify 2b1815fd9SAlexander Aring * it under the terms of the GNU General Public License version 2 3b1815fd9SAlexander Aring * as published by the Free Software Foundation. 4b1815fd9SAlexander Aring * 5b1815fd9SAlexander Aring * This program is distributed in the hope that it will be useful, 6b1815fd9SAlexander Aring * but WITHOUT ANY WARRANTY; without even the implied warranty of 7b1815fd9SAlexander Aring * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8b1815fd9SAlexander Aring * GNU General Public License for more details. 9b1815fd9SAlexander Aring * 10b1815fd9SAlexander Aring * Authors: 11b1815fd9SAlexander Aring * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 12b1815fd9SAlexander Aring * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. 13b1815fd9SAlexander Aring */ 14b1815fd9SAlexander Aring 15b1815fd9SAlexander Aring #include <net/6lowpan.h> 16b1815fd9SAlexander Aring 17b1815fd9SAlexander Aring #include "6lowpan_i.h" 18b1815fd9SAlexander Aring 195609c185SAlexander Aring #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8 205609c185SAlexander Aring 21b1815fd9SAlexander Aring static struct dentry *lowpan_debugfs; 22b1815fd9SAlexander Aring 235609c185SAlexander Aring static int lowpan_ctx_flag_active_set(void *data, u64 val) 245609c185SAlexander Aring { 255609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 265609c185SAlexander Aring 275609c185SAlexander Aring if (val != 0 && val != 1) 285609c185SAlexander Aring return -EINVAL; 295609c185SAlexander Aring 305609c185SAlexander Aring if (val) 315609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 325609c185SAlexander Aring else 335609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 345609c185SAlexander Aring 355609c185SAlexander Aring return 0; 365609c185SAlexander Aring } 375609c185SAlexander Aring 385609c185SAlexander Aring static int lowpan_ctx_flag_active_get(void *data, u64 *val) 395609c185SAlexander Aring { 405609c185SAlexander Aring *val = lowpan_iphc_ctx_is_active(data); 415609c185SAlexander Aring return 0; 425609c185SAlexander Aring } 435609c185SAlexander Aring 44*5e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_active_fops, 455609c185SAlexander Aring lowpan_ctx_flag_active_get, 465609c185SAlexander Aring lowpan_ctx_flag_active_set, "%llu\n"); 475609c185SAlexander Aring 485609c185SAlexander Aring static int lowpan_ctx_flag_c_set(void *data, u64 val) 495609c185SAlexander Aring { 505609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 515609c185SAlexander Aring 525609c185SAlexander Aring if (val != 0 && val != 1) 535609c185SAlexander Aring return -EINVAL; 545609c185SAlexander Aring 555609c185SAlexander Aring if (val) 565609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 575609c185SAlexander Aring else 585609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 595609c185SAlexander Aring 605609c185SAlexander Aring return 0; 615609c185SAlexander Aring } 625609c185SAlexander Aring 635609c185SAlexander Aring static int lowpan_ctx_flag_c_get(void *data, u64 *val) 645609c185SAlexander Aring { 655609c185SAlexander Aring *val = lowpan_iphc_ctx_is_compression(data); 665609c185SAlexander Aring return 0; 675609c185SAlexander Aring } 685609c185SAlexander Aring 69*5e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get, 705609c185SAlexander Aring lowpan_ctx_flag_c_set, "%llu\n"); 715609c185SAlexander Aring 725609c185SAlexander Aring static int lowpan_ctx_plen_set(void *data, u64 val) 735609c185SAlexander Aring { 745609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 755609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 765609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 775609c185SAlexander Aring 785609c185SAlexander Aring if (val > 128) 795609c185SAlexander Aring return -EINVAL; 805609c185SAlexander Aring 815609c185SAlexander Aring spin_lock_bh(&t->lock); 825609c185SAlexander Aring ctx->plen = val; 835609c185SAlexander Aring spin_unlock_bh(&t->lock); 845609c185SAlexander Aring 855609c185SAlexander Aring return 0; 865609c185SAlexander Aring } 875609c185SAlexander Aring 885609c185SAlexander Aring static int lowpan_ctx_plen_get(void *data, u64 *val) 895609c185SAlexander Aring { 905609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 915609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 925609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 935609c185SAlexander Aring 945609c185SAlexander Aring spin_lock_bh(&t->lock); 955609c185SAlexander Aring *val = ctx->plen; 965609c185SAlexander Aring spin_unlock_bh(&t->lock); 975609c185SAlexander Aring return 0; 985609c185SAlexander Aring } 995609c185SAlexander Aring 100*5e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get, 1015609c185SAlexander Aring lowpan_ctx_plen_set, "%llu\n"); 1025609c185SAlexander Aring 1035609c185SAlexander Aring static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset) 1045609c185SAlexander Aring { 1055609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1065609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1075609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1085609c185SAlexander Aring 1095609c185SAlexander Aring spin_lock_bh(&t->lock); 1105609c185SAlexander Aring seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 1115609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[0]), 1125609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[1]), 1135609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[2]), 1145609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[3]), 1155609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[4]), 1165609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[5]), 1175609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[6]), 1185609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[7])); 1195609c185SAlexander Aring spin_unlock_bh(&t->lock); 1205609c185SAlexander Aring 1215609c185SAlexander Aring return 0; 1225609c185SAlexander Aring } 1235609c185SAlexander Aring 1245609c185SAlexander Aring static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file) 1255609c185SAlexander Aring { 1265609c185SAlexander Aring return single_open(file, lowpan_ctx_pfx_show, inode->i_private); 1275609c185SAlexander Aring } 1285609c185SAlexander Aring 1295609c185SAlexander Aring static ssize_t lowpan_ctx_pfx_write(struct file *fp, 1305609c185SAlexander Aring const char __user *user_buf, size_t count, 1315609c185SAlexander Aring loff_t *ppos) 1325609c185SAlexander Aring { 1335609c185SAlexander Aring char buf[128] = {}; 1345609c185SAlexander Aring struct seq_file *file = fp->private_data; 1355609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1365609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1375609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1385609c185SAlexander Aring int status = count, n, i; 1395609c185SAlexander Aring unsigned int addr[8]; 1405609c185SAlexander Aring 1415609c185SAlexander Aring if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1, 1425609c185SAlexander Aring count))) { 1435609c185SAlexander Aring status = -EFAULT; 1445609c185SAlexander Aring goto out; 1455609c185SAlexander Aring } 1465609c185SAlexander Aring 1475609c185SAlexander Aring n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 1485609c185SAlexander Aring &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], 1495609c185SAlexander Aring &addr[5], &addr[6], &addr[7]); 1505609c185SAlexander Aring if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) { 1515609c185SAlexander Aring status = -EINVAL; 1525609c185SAlexander Aring goto out; 1535609c185SAlexander Aring } 1545609c185SAlexander Aring 1555609c185SAlexander Aring spin_lock_bh(&t->lock); 1565609c185SAlexander Aring for (i = 0; i < 8; i++) 1575609c185SAlexander Aring ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff); 1585609c185SAlexander Aring spin_unlock_bh(&t->lock); 1595609c185SAlexander Aring 1605609c185SAlexander Aring out: 1615609c185SAlexander Aring return status; 1625609c185SAlexander Aring } 1635609c185SAlexander Aring 1646aaf37b4SAlexander Aring static const struct file_operations lowpan_ctx_pfx_fops = { 1655609c185SAlexander Aring .open = lowpan_ctx_pfx_open, 1665609c185SAlexander Aring .read = seq_read, 1675609c185SAlexander Aring .write = lowpan_ctx_pfx_write, 1685609c185SAlexander Aring .llseek = seq_lseek, 1695609c185SAlexander Aring .release = single_release, 1705609c185SAlexander Aring }; 1715609c185SAlexander Aring 1725609c185SAlexander Aring static int lowpan_dev_debugfs_ctx_init(struct net_device *dev, 1735609c185SAlexander Aring struct dentry *ctx, u8 id) 1745609c185SAlexander Aring { 1752e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 1765609c185SAlexander Aring struct dentry *dentry, *root; 1775609c185SAlexander Aring char buf[32]; 1785609c185SAlexander Aring 1795609c185SAlexander Aring WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE); 1805609c185SAlexander Aring 1815609c185SAlexander Aring sprintf(buf, "%d", id); 1825609c185SAlexander Aring 1835609c185SAlexander Aring root = debugfs_create_dir(buf, ctx); 1845609c185SAlexander Aring if (!root) 1855609c185SAlexander Aring return -EINVAL; 1865609c185SAlexander Aring 187*5e053534SYueHaibing dentry = debugfs_create_file_unsafe("active", 0644, root, 1882e4d60cbSAlexander Aring &ldev->ctx.table[id], 1895609c185SAlexander Aring &lowpan_ctx_flag_active_fops); 1905609c185SAlexander Aring if (!dentry) 1915609c185SAlexander Aring return -EINVAL; 1925609c185SAlexander Aring 193*5e053534SYueHaibing dentry = debugfs_create_file_unsafe("compression", 0644, root, 1942e4d60cbSAlexander Aring &ldev->ctx.table[id], 1955609c185SAlexander Aring &lowpan_ctx_flag_c_fops); 1965609c185SAlexander Aring if (!dentry) 1975609c185SAlexander Aring return -EINVAL; 1985609c185SAlexander Aring 1995609c185SAlexander Aring dentry = debugfs_create_file("prefix", 0644, root, 2002e4d60cbSAlexander Aring &ldev->ctx.table[id], 2015609c185SAlexander Aring &lowpan_ctx_pfx_fops); 2025609c185SAlexander Aring if (!dentry) 2035609c185SAlexander Aring return -EINVAL; 2045609c185SAlexander Aring 205*5e053534SYueHaibing dentry = debugfs_create_file_unsafe("prefix_len", 0644, root, 2062e4d60cbSAlexander Aring &ldev->ctx.table[id], 2075609c185SAlexander Aring &lowpan_ctx_plen_fops); 2085609c185SAlexander Aring if (!dentry) 2095609c185SAlexander Aring return -EINVAL; 2105609c185SAlexander Aring 2115609c185SAlexander Aring return 0; 2125609c185SAlexander Aring } 2135609c185SAlexander Aring 2145609c185SAlexander Aring static int lowpan_context_show(struct seq_file *file, void *offset) 2155609c185SAlexander Aring { 2165609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = file->private; 2175609c185SAlexander Aring int i; 2185609c185SAlexander Aring 2195609c185SAlexander Aring seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C'); 2205609c185SAlexander Aring seq_puts(file, "-------------------------------------------------\n"); 2215609c185SAlexander Aring 2225609c185SAlexander Aring spin_lock_bh(&t->lock); 2235609c185SAlexander Aring for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2245609c185SAlexander Aring if (!lowpan_iphc_ctx_is_active(&t->table[i])) 2255609c185SAlexander Aring continue; 2265609c185SAlexander Aring 2275609c185SAlexander Aring seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id, 2285609c185SAlexander Aring &t->table[i].pfx, t->table[i].plen, 2295609c185SAlexander Aring lowpan_iphc_ctx_is_compression(&t->table[i])); 2305609c185SAlexander Aring } 2315609c185SAlexander Aring spin_unlock_bh(&t->lock); 2325609c185SAlexander Aring 2335609c185SAlexander Aring return 0; 2345609c185SAlexander Aring } 235f79ba430SYangtao Li DEFINE_SHOW_ATTRIBUTE(lowpan_context); 2365609c185SAlexander Aring 237cfce9465SAlexander Aring static int lowpan_short_addr_get(void *data, u64 *val) 238cfce9465SAlexander Aring { 239cfce9465SAlexander Aring struct wpan_dev *wdev = data; 240cfce9465SAlexander Aring 241cfce9465SAlexander Aring rtnl_lock(); 242cfce9465SAlexander Aring *val = le16_to_cpu(wdev->short_addr); 243cfce9465SAlexander Aring rtnl_unlock(); 244cfce9465SAlexander Aring 245cfce9465SAlexander Aring return 0; 246cfce9465SAlexander Aring } 247cfce9465SAlexander Aring 248*5e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get, NULL, 249*5e053534SYueHaibing "0x%04llx\n"); 250cfce9465SAlexander Aring 251cfce9465SAlexander Aring static int lowpan_dev_debugfs_802154_init(const struct net_device *dev, 252cfce9465SAlexander Aring struct lowpan_dev *ldev) 253cfce9465SAlexander Aring { 254cfce9465SAlexander Aring struct dentry *dentry, *root; 255cfce9465SAlexander Aring 256cfce9465SAlexander Aring if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) 257cfce9465SAlexander Aring return 0; 258cfce9465SAlexander Aring 259cfce9465SAlexander Aring root = debugfs_create_dir("ieee802154", ldev->iface_debugfs); 260cfce9465SAlexander Aring if (!root) 261cfce9465SAlexander Aring return -EINVAL; 262cfce9465SAlexander Aring 263*5e053534SYueHaibing dentry = debugfs_create_file_unsafe("short_addr", 0444, root, 264cfce9465SAlexander Aring lowpan_802154_dev(dev)->wdev->ieee802154_ptr, 265cfce9465SAlexander Aring &lowpan_short_addr_fops); 266cfce9465SAlexander Aring if (!dentry) 267cfce9465SAlexander Aring return -EINVAL; 268cfce9465SAlexander Aring 269cfce9465SAlexander Aring return 0; 270cfce9465SAlexander Aring } 271cfce9465SAlexander Aring 272b1815fd9SAlexander Aring int lowpan_dev_debugfs_init(struct net_device *dev) 273b1815fd9SAlexander Aring { 2742e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 2755609c185SAlexander Aring struct dentry *contexts, *dentry; 2765609c185SAlexander Aring int ret, i; 277b1815fd9SAlexander Aring 278b1815fd9SAlexander Aring /* creating the root */ 2792e4d60cbSAlexander Aring ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs); 2802e4d60cbSAlexander Aring if (!ldev->iface_debugfs) 281b1815fd9SAlexander Aring goto fail; 282b1815fd9SAlexander Aring 2832e4d60cbSAlexander Aring contexts = debugfs_create_dir("contexts", ldev->iface_debugfs); 2845609c185SAlexander Aring if (!contexts) 2855609c185SAlexander Aring goto remove_root; 2865609c185SAlexander Aring 2875609c185SAlexander Aring dentry = debugfs_create_file("show", 0644, contexts, 2882e4d60cbSAlexander Aring &lowpan_dev(dev)->ctx, 2895609c185SAlexander Aring &lowpan_context_fops); 2905609c185SAlexander Aring if (!dentry) 2915609c185SAlexander Aring goto remove_root; 2925609c185SAlexander Aring 2935609c185SAlexander Aring for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2945609c185SAlexander Aring ret = lowpan_dev_debugfs_ctx_init(dev, contexts, i); 2955609c185SAlexander Aring if (ret < 0) 2965609c185SAlexander Aring goto remove_root; 2975609c185SAlexander Aring } 2985609c185SAlexander Aring 299cfce9465SAlexander Aring ret = lowpan_dev_debugfs_802154_init(dev, ldev); 300cfce9465SAlexander Aring if (ret < 0) 301cfce9465SAlexander Aring goto remove_root; 302cfce9465SAlexander Aring 303b1815fd9SAlexander Aring return 0; 304b1815fd9SAlexander Aring 3055609c185SAlexander Aring remove_root: 3065609c185SAlexander Aring lowpan_dev_debugfs_exit(dev); 307b1815fd9SAlexander Aring fail: 308b1815fd9SAlexander Aring return -EINVAL; 309b1815fd9SAlexander Aring } 310b1815fd9SAlexander Aring 311b1815fd9SAlexander Aring void lowpan_dev_debugfs_exit(struct net_device *dev) 312b1815fd9SAlexander Aring { 3132e4d60cbSAlexander Aring debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs); 314b1815fd9SAlexander Aring } 315b1815fd9SAlexander Aring 316b1815fd9SAlexander Aring int __init lowpan_debugfs_init(void) 317b1815fd9SAlexander Aring { 318b1815fd9SAlexander Aring lowpan_debugfs = debugfs_create_dir("6lowpan", NULL); 319b1815fd9SAlexander Aring if (!lowpan_debugfs) 320b1815fd9SAlexander Aring return -EINVAL; 321b1815fd9SAlexander Aring 322b1815fd9SAlexander Aring return 0; 323b1815fd9SAlexander Aring } 324b1815fd9SAlexander Aring 325b1815fd9SAlexander Aring void lowpan_debugfs_exit(void) 326b1815fd9SAlexander Aring { 327b1815fd9SAlexander Aring debugfs_remove_recursive(lowpan_debugfs); 328b1815fd9SAlexander Aring } 329