18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Authors: 58c2ecf20Sopenharmony_ci * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 68c2ecf20Sopenharmony_ci * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <net/6lowpan.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "6lowpan_i.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct dentry *lowpan_debugfs; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int lowpan_ctx_flag_active_set(void *data, u64 val) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = data; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci if (val != 0 && val != 1) 228c2ecf20Sopenharmony_ci return -EINVAL; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (val) 258c2ecf20Sopenharmony_ci set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 268c2ecf20Sopenharmony_ci else 278c2ecf20Sopenharmony_ci clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return 0; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int lowpan_ctx_flag_active_get(void *data, u64 *val) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci *val = lowpan_iphc_ctx_is_active(data); 358c2ecf20Sopenharmony_ci return 0; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_active_fops, 398c2ecf20Sopenharmony_ci lowpan_ctx_flag_active_get, 408c2ecf20Sopenharmony_ci lowpan_ctx_flag_active_set, "%llu\n"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int lowpan_ctx_flag_c_set(void *data, u64 val) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = data; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (val != 0 && val != 1) 478c2ecf20Sopenharmony_ci return -EINVAL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (val) 508c2ecf20Sopenharmony_ci set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int lowpan_ctx_flag_c_get(void *data, u64 *val) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci *val = lowpan_iphc_ctx_is_compression(data); 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get, 648c2ecf20Sopenharmony_ci lowpan_ctx_flag_c_set, "%llu\n"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int lowpan_ctx_plen_set(void *data, u64 val) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = data; 698c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx_table *t = 708c2ecf20Sopenharmony_ci container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (val > 128) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci spin_lock_bh(&t->lock); 768c2ecf20Sopenharmony_ci ctx->plen = val; 778c2ecf20Sopenharmony_ci spin_unlock_bh(&t->lock); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int lowpan_ctx_plen_get(void *data, u64 *val) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = data; 858c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx_table *t = 868c2ecf20Sopenharmony_ci container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci spin_lock_bh(&t->lock); 898c2ecf20Sopenharmony_ci *val = ctx->plen; 908c2ecf20Sopenharmony_ci spin_unlock_bh(&t->lock); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get, 958c2ecf20Sopenharmony_ci lowpan_ctx_plen_set, "%llu\n"); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int lowpan_ctx_pfx_show(struct seq_file *file, void *offset) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = file->private; 1008c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx_table *t = 1018c2ecf20Sopenharmony_ci container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spin_lock_bh(&t->lock); 1048c2ecf20Sopenharmony_ci seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 1058c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[0]), 1068c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[1]), 1078c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[2]), 1088c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[3]), 1098c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[4]), 1108c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[5]), 1118c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[6]), 1128c2ecf20Sopenharmony_ci be16_to_cpu(ctx->pfx.s6_addr16[7])); 1138c2ecf20Sopenharmony_ci spin_unlock_bh(&t->lock); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int lowpan_ctx_pfx_open(struct inode *inode, struct file *file) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return single_open(file, lowpan_ctx_pfx_show, inode->i_private); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic ssize_t lowpan_ctx_pfx_write(struct file *fp, 1248c2ecf20Sopenharmony_ci const char __user *user_buf, size_t count, 1258c2ecf20Sopenharmony_ci loff_t *ppos) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci char buf[128] = {}; 1288c2ecf20Sopenharmony_ci struct seq_file *file = fp->private_data; 1298c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx = file->private; 1308c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx_table *t = 1318c2ecf20Sopenharmony_ci container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1328c2ecf20Sopenharmony_ci int status = count, n, i; 1338c2ecf20Sopenharmony_ci unsigned int addr[8]; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1, 1368c2ecf20Sopenharmony_ci count))) { 1378c2ecf20Sopenharmony_ci status = -EFAULT; 1388c2ecf20Sopenharmony_ci goto out; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 1428c2ecf20Sopenharmony_ci &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], 1438c2ecf20Sopenharmony_ci &addr[5], &addr[6], &addr[7]); 1448c2ecf20Sopenharmony_ci if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) { 1458c2ecf20Sopenharmony_ci status = -EINVAL; 1468c2ecf20Sopenharmony_ci goto out; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci spin_lock_bh(&t->lock); 1508c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 1518c2ecf20Sopenharmony_ci ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff); 1528c2ecf20Sopenharmony_ci spin_unlock_bh(&t->lock); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciout: 1558c2ecf20Sopenharmony_ci return status; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct file_operations lowpan_ctx_pfx_fops = { 1598c2ecf20Sopenharmony_ci .open = lowpan_ctx_pfx_open, 1608c2ecf20Sopenharmony_ci .read = seq_read, 1618c2ecf20Sopenharmony_ci .write = lowpan_ctx_pfx_write, 1628c2ecf20Sopenharmony_ci .llseek = seq_lseek, 1638c2ecf20Sopenharmony_ci .release = single_release, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void lowpan_dev_debugfs_ctx_init(struct net_device *dev, 1678c2ecf20Sopenharmony_ci struct dentry *ctx, u8 id) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct lowpan_dev *ldev = lowpan_dev(dev); 1708c2ecf20Sopenharmony_ci struct dentry *root; 1718c2ecf20Sopenharmony_ci char buf[32]; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(id >= LOWPAN_IPHC_CTX_TABLE_SIZE)) 1748c2ecf20Sopenharmony_ci return; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci sprintf(buf, "%d", id); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci root = debugfs_create_dir(buf, ctx); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci debugfs_create_file("active", 0644, root, &ldev->ctx.table[id], 1818c2ecf20Sopenharmony_ci &lowpan_ctx_flag_active_fops); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci debugfs_create_file("compression", 0644, root, &ldev->ctx.table[id], 1848c2ecf20Sopenharmony_ci &lowpan_ctx_flag_c_fops); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci debugfs_create_file("prefix", 0644, root, &ldev->ctx.table[id], 1878c2ecf20Sopenharmony_ci &lowpan_ctx_pfx_fops); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci debugfs_create_file("prefix_len", 0644, root, &ldev->ctx.table[id], 1908c2ecf20Sopenharmony_ci &lowpan_ctx_plen_fops); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int lowpan_context_show(struct seq_file *file, void *offset) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx_table *t = file->private; 1968c2ecf20Sopenharmony_ci int i; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C'); 1998c2ecf20Sopenharmony_ci seq_puts(file, "-------------------------------------------------\n"); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci spin_lock_bh(&t->lock); 2028c2ecf20Sopenharmony_ci for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2038c2ecf20Sopenharmony_ci if (!lowpan_iphc_ctx_is_active(&t->table[i])) 2048c2ecf20Sopenharmony_ci continue; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id, 2078c2ecf20Sopenharmony_ci &t->table[i].pfx, t->table[i].plen, 2088c2ecf20Sopenharmony_ci lowpan_iphc_ctx_is_compression(&t->table[i])); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci spin_unlock_bh(&t->lock); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(lowpan_context); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int lowpan_short_addr_get(void *data, u64 *val) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct wpan_dev *wdev = data; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci rtnl_lock(); 2218c2ecf20Sopenharmony_ci *val = le16_to_cpu(wdev->short_addr); 2228c2ecf20Sopenharmony_ci rtnl_unlock(); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get, NULL, 2288c2ecf20Sopenharmony_ci "0x%04llx\n"); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic void lowpan_dev_debugfs_802154_init(const struct net_device *dev, 2318c2ecf20Sopenharmony_ci struct lowpan_dev *ldev) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct dentry *root; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) 2368c2ecf20Sopenharmony_ci return; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci root = debugfs_create_dir("ieee802154", ldev->iface_debugfs); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci debugfs_create_file("short_addr", 0444, root, 2418c2ecf20Sopenharmony_ci lowpan_802154_dev(dev)->wdev->ieee802154_ptr, 2428c2ecf20Sopenharmony_ci &lowpan_short_addr_fops); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_civoid lowpan_dev_debugfs_init(struct net_device *dev) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct lowpan_dev *ldev = lowpan_dev(dev); 2488c2ecf20Sopenharmony_ci struct dentry *contexts; 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* creating the root */ 2528c2ecf20Sopenharmony_ci ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci contexts = debugfs_create_dir("contexts", ldev->iface_debugfs); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci debugfs_create_file("show", 0644, contexts, &lowpan_dev(dev)->ctx, 2578c2ecf20Sopenharmony_ci &lowpan_context_fops); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) 2608c2ecf20Sopenharmony_ci lowpan_dev_debugfs_ctx_init(dev, contexts, i); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci lowpan_dev_debugfs_802154_init(dev, ldev); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_civoid lowpan_dev_debugfs_exit(struct net_device *dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_civoid __init lowpan_debugfs_init(void) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci lowpan_debugfs = debugfs_create_dir("6lowpan", NULL); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_civoid lowpan_debugfs_exit(void) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci debugfs_remove_recursive(lowpan_debugfs); 2788c2ecf20Sopenharmony_ci} 279