11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21802d0beSThomas Gleixner /* 3b1815fd9SAlexander Aring * 4b1815fd9SAlexander Aring * Authors: 5b1815fd9SAlexander Aring * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 6b1815fd9SAlexander Aring * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. 7b1815fd9SAlexander Aring */ 8b1815fd9SAlexander Aring 9b1815fd9SAlexander Aring #include <net/6lowpan.h> 10b1815fd9SAlexander Aring 11b1815fd9SAlexander Aring #include "6lowpan_i.h" 12b1815fd9SAlexander Aring 135609c185SAlexander Aring #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8 145609c185SAlexander Aring 15b1815fd9SAlexander Aring static struct dentry *lowpan_debugfs; 16b1815fd9SAlexander Aring 175609c185SAlexander Aring static int lowpan_ctx_flag_active_set(void *data, u64 val) 185609c185SAlexander Aring { 195609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 205609c185SAlexander Aring 215609c185SAlexander Aring if (val != 0 && val != 1) 225609c185SAlexander Aring return -EINVAL; 235609c185SAlexander Aring 245609c185SAlexander Aring if (val) 255609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 265609c185SAlexander Aring else 275609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 285609c185SAlexander Aring 295609c185SAlexander Aring return 0; 305609c185SAlexander Aring } 315609c185SAlexander Aring 325609c185SAlexander Aring static int lowpan_ctx_flag_active_get(void *data, u64 *val) 335609c185SAlexander Aring { 345609c185SAlexander Aring *val = lowpan_iphc_ctx_is_active(data); 355609c185SAlexander Aring return 0; 365609c185SAlexander Aring } 375609c185SAlexander Aring 385e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_active_fops, 395609c185SAlexander Aring lowpan_ctx_flag_active_get, 405609c185SAlexander Aring lowpan_ctx_flag_active_set, "%llu\n"); 415609c185SAlexander Aring 425609c185SAlexander Aring static int lowpan_ctx_flag_c_set(void *data, u64 val) 435609c185SAlexander Aring { 445609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 455609c185SAlexander Aring 465609c185SAlexander Aring if (val != 0 && val != 1) 475609c185SAlexander Aring return -EINVAL; 485609c185SAlexander Aring 495609c185SAlexander Aring if (val) 505609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 515609c185SAlexander Aring else 525609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 535609c185SAlexander Aring 545609c185SAlexander Aring return 0; 555609c185SAlexander Aring } 565609c185SAlexander Aring 575609c185SAlexander Aring static int lowpan_ctx_flag_c_get(void *data, u64 *val) 585609c185SAlexander Aring { 595609c185SAlexander Aring *val = lowpan_iphc_ctx_is_compression(data); 605609c185SAlexander Aring return 0; 615609c185SAlexander Aring } 625609c185SAlexander Aring 635e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get, 645609c185SAlexander Aring lowpan_ctx_flag_c_set, "%llu\n"); 655609c185SAlexander Aring 665609c185SAlexander Aring static int lowpan_ctx_plen_set(void *data, u64 val) 675609c185SAlexander Aring { 685609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 695609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 705609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 715609c185SAlexander Aring 725609c185SAlexander Aring if (val > 128) 735609c185SAlexander Aring return -EINVAL; 745609c185SAlexander Aring 755609c185SAlexander Aring spin_lock_bh(&t->lock); 765609c185SAlexander Aring ctx->plen = val; 775609c185SAlexander Aring spin_unlock_bh(&t->lock); 785609c185SAlexander Aring 795609c185SAlexander Aring return 0; 805609c185SAlexander Aring } 815609c185SAlexander Aring 825609c185SAlexander Aring static int lowpan_ctx_plen_get(void *data, u64 *val) 835609c185SAlexander Aring { 845609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 855609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 865609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 875609c185SAlexander Aring 885609c185SAlexander Aring spin_lock_bh(&t->lock); 895609c185SAlexander Aring *val = ctx->plen; 905609c185SAlexander Aring spin_unlock_bh(&t->lock); 915609c185SAlexander Aring return 0; 925609c185SAlexander Aring } 935609c185SAlexander Aring 945e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get, 955609c185SAlexander Aring lowpan_ctx_plen_set, "%llu\n"); 965609c185SAlexander Aring 975609c185SAlexander Aring static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset) 985609c185SAlexander Aring { 995609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1005609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1015609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1025609c185SAlexander Aring 1035609c185SAlexander Aring spin_lock_bh(&t->lock); 1045609c185SAlexander Aring seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 1055609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[0]), 1065609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[1]), 1075609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[2]), 1085609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[3]), 1095609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[4]), 1105609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[5]), 1115609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[6]), 1125609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[7])); 1135609c185SAlexander Aring spin_unlock_bh(&t->lock); 1145609c185SAlexander Aring 1155609c185SAlexander Aring return 0; 1165609c185SAlexander Aring } 1175609c185SAlexander Aring 1185609c185SAlexander Aring static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file) 1195609c185SAlexander Aring { 1205609c185SAlexander Aring return single_open(file, lowpan_ctx_pfx_show, inode->i_private); 1215609c185SAlexander Aring } 1225609c185SAlexander Aring 1235609c185SAlexander Aring static ssize_t lowpan_ctx_pfx_write(struct file *fp, 1245609c185SAlexander Aring const char __user *user_buf, size_t count, 1255609c185SAlexander Aring loff_t *ppos) 1265609c185SAlexander Aring { 1275609c185SAlexander Aring char buf[128] = {}; 1285609c185SAlexander Aring struct seq_file *file = fp->private_data; 1295609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1305609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1315609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1325609c185SAlexander Aring int status = count, n, i; 1335609c185SAlexander Aring unsigned int addr[8]; 1345609c185SAlexander Aring 1355609c185SAlexander Aring if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1, 1365609c185SAlexander Aring count))) { 1375609c185SAlexander Aring status = -EFAULT; 1385609c185SAlexander Aring goto out; 1395609c185SAlexander Aring } 1405609c185SAlexander Aring 1415609c185SAlexander Aring n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 1425609c185SAlexander Aring &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], 1435609c185SAlexander Aring &addr[5], &addr[6], &addr[7]); 1445609c185SAlexander Aring if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) { 1455609c185SAlexander Aring status = -EINVAL; 1465609c185SAlexander Aring goto out; 1475609c185SAlexander Aring } 1485609c185SAlexander Aring 1495609c185SAlexander Aring spin_lock_bh(&t->lock); 1505609c185SAlexander Aring for (i = 0; i < 8; i++) 1515609c185SAlexander Aring ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff); 1525609c185SAlexander Aring spin_unlock_bh(&t->lock); 1535609c185SAlexander Aring 1545609c185SAlexander Aring out: 1555609c185SAlexander Aring return status; 1565609c185SAlexander Aring } 1575609c185SAlexander Aring 1586aaf37b4SAlexander Aring static const struct file_operations lowpan_ctx_pfx_fops = { 1595609c185SAlexander Aring .open = lowpan_ctx_pfx_open, 1605609c185SAlexander Aring .read = seq_read, 1615609c185SAlexander Aring .write = lowpan_ctx_pfx_write, 1625609c185SAlexander Aring .llseek = seq_lseek, 1635609c185SAlexander Aring .release = single_release, 1645609c185SAlexander Aring }; 1655609c185SAlexander Aring 166*db50450dSGreg Kroah-Hartman static void lowpan_dev_debugfs_ctx_init(struct net_device *dev, 1675609c185SAlexander Aring struct dentry *ctx, u8 id) 1685609c185SAlexander Aring { 1692e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 170*db50450dSGreg Kroah-Hartman struct dentry *root; 1715609c185SAlexander Aring char buf[32]; 1725609c185SAlexander Aring 1735609c185SAlexander Aring WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE); 1745609c185SAlexander Aring 1755609c185SAlexander Aring sprintf(buf, "%d", id); 1765609c185SAlexander Aring 1775609c185SAlexander Aring root = debugfs_create_dir(buf, ctx); 1785609c185SAlexander Aring 179*db50450dSGreg Kroah-Hartman debugfs_create_file("active", 0644, root, &ldev->ctx.table[id], 1805609c185SAlexander Aring &lowpan_ctx_flag_active_fops); 1815609c185SAlexander Aring 182*db50450dSGreg Kroah-Hartman debugfs_create_file("compression", 0644, root, &ldev->ctx.table[id], 1835609c185SAlexander Aring &lowpan_ctx_flag_c_fops); 1845609c185SAlexander Aring 185*db50450dSGreg Kroah-Hartman debugfs_create_file("prefix", 0644, root, &ldev->ctx.table[id], 1865609c185SAlexander Aring &lowpan_ctx_pfx_fops); 1875609c185SAlexander Aring 188*db50450dSGreg Kroah-Hartman debugfs_create_file("prefix_len", 0644, root, &ldev->ctx.table[id], 1895609c185SAlexander Aring &lowpan_ctx_plen_fops); 1905609c185SAlexander Aring } 1915609c185SAlexander Aring 1925609c185SAlexander Aring static int lowpan_context_show(struct seq_file *file, void *offset) 1935609c185SAlexander Aring { 1945609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = file->private; 1955609c185SAlexander Aring int i; 1965609c185SAlexander Aring 1975609c185SAlexander Aring seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C'); 1985609c185SAlexander Aring seq_puts(file, "-------------------------------------------------\n"); 1995609c185SAlexander Aring 2005609c185SAlexander Aring spin_lock_bh(&t->lock); 2015609c185SAlexander Aring for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2025609c185SAlexander Aring if (!lowpan_iphc_ctx_is_active(&t->table[i])) 2035609c185SAlexander Aring continue; 2045609c185SAlexander Aring 2055609c185SAlexander Aring seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id, 2065609c185SAlexander Aring &t->table[i].pfx, t->table[i].plen, 2075609c185SAlexander Aring lowpan_iphc_ctx_is_compression(&t->table[i])); 2085609c185SAlexander Aring } 2095609c185SAlexander Aring spin_unlock_bh(&t->lock); 2105609c185SAlexander Aring 2115609c185SAlexander Aring return 0; 2125609c185SAlexander Aring } 213f79ba430SYangtao Li DEFINE_SHOW_ATTRIBUTE(lowpan_context); 2145609c185SAlexander Aring 215cfce9465SAlexander Aring static int lowpan_short_addr_get(void *data, u64 *val) 216cfce9465SAlexander Aring { 217cfce9465SAlexander Aring struct wpan_dev *wdev = data; 218cfce9465SAlexander Aring 219cfce9465SAlexander Aring rtnl_lock(); 220cfce9465SAlexander Aring *val = le16_to_cpu(wdev->short_addr); 221cfce9465SAlexander Aring rtnl_unlock(); 222cfce9465SAlexander Aring 223cfce9465SAlexander Aring return 0; 224cfce9465SAlexander Aring } 225cfce9465SAlexander Aring 2265e053534SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get, NULL, 2275e053534SYueHaibing "0x%04llx\n"); 228cfce9465SAlexander Aring 229*db50450dSGreg Kroah-Hartman static void lowpan_dev_debugfs_802154_init(const struct net_device *dev, 230cfce9465SAlexander Aring struct lowpan_dev *ldev) 231cfce9465SAlexander Aring { 232*db50450dSGreg Kroah-Hartman struct dentry *root; 233cfce9465SAlexander Aring 234cfce9465SAlexander Aring if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) 235*db50450dSGreg Kroah-Hartman return; 236cfce9465SAlexander Aring 237cfce9465SAlexander Aring root = debugfs_create_dir("ieee802154", ldev->iface_debugfs); 238cfce9465SAlexander Aring 239*db50450dSGreg Kroah-Hartman debugfs_create_file("short_addr", 0444, root, 240cfce9465SAlexander Aring lowpan_802154_dev(dev)->wdev->ieee802154_ptr, 241cfce9465SAlexander Aring &lowpan_short_addr_fops); 242cfce9465SAlexander Aring } 243cfce9465SAlexander Aring 244*db50450dSGreg Kroah-Hartman void lowpan_dev_debugfs_init(struct net_device *dev) 245b1815fd9SAlexander Aring { 2462e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 247*db50450dSGreg Kroah-Hartman struct dentry *contexts; 248*db50450dSGreg Kroah-Hartman int i; 249b1815fd9SAlexander Aring 250b1815fd9SAlexander Aring /* creating the root */ 2512e4d60cbSAlexander Aring ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs); 252b1815fd9SAlexander Aring 2532e4d60cbSAlexander Aring contexts = debugfs_create_dir("contexts", ldev->iface_debugfs); 2545609c185SAlexander Aring 255*db50450dSGreg Kroah-Hartman debugfs_create_file("show", 0644, contexts, &lowpan_dev(dev)->ctx, 2565609c185SAlexander Aring &lowpan_context_fops); 2575609c185SAlexander Aring 258*db50450dSGreg Kroah-Hartman for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) 259*db50450dSGreg Kroah-Hartman lowpan_dev_debugfs_ctx_init(dev, contexts, i); 2605609c185SAlexander Aring 261*db50450dSGreg Kroah-Hartman lowpan_dev_debugfs_802154_init(dev, ldev); 262b1815fd9SAlexander Aring } 263b1815fd9SAlexander Aring 264b1815fd9SAlexander Aring void lowpan_dev_debugfs_exit(struct net_device *dev) 265b1815fd9SAlexander Aring { 2662e4d60cbSAlexander Aring debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs); 267b1815fd9SAlexander Aring } 268b1815fd9SAlexander Aring 269*db50450dSGreg Kroah-Hartman void __init lowpan_debugfs_init(void) 270b1815fd9SAlexander Aring { 271b1815fd9SAlexander Aring lowpan_debugfs = debugfs_create_dir("6lowpan", NULL); 272b1815fd9SAlexander Aring } 273b1815fd9SAlexander Aring 274b1815fd9SAlexander Aring void lowpan_debugfs_exit(void) 275b1815fd9SAlexander Aring { 276b1815fd9SAlexander Aring debugfs_remove_recursive(lowpan_debugfs); 277b1815fd9SAlexander Aring } 278