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.
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.
11 * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
12 * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
15 #include <net/6lowpan.h>
17 #include "6lowpan_i.h"
19 #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8
21 static struct dentry
*lowpan_debugfs
;
23 static int lowpan_ctx_flag_active_set(void *data
, u64 val
)
25 struct lowpan_iphc_ctx
*ctx
= data
;
27 if (val
!= 0 && val
!= 1)
31 set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE
, &ctx
->flags
);
33 clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE
, &ctx
->flags
);
38 static int lowpan_ctx_flag_active_get(void *data
, u64
*val
)
40 *val
= lowpan_iphc_ctx_is_active(data
);
44 DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops
,
45 lowpan_ctx_flag_active_get
,
46 lowpan_ctx_flag_active_set
, "%llu\n");
48 static int lowpan_ctx_flag_c_set(void *data
, u64 val
)
50 struct lowpan_iphc_ctx
*ctx
= data
;
52 if (val
!= 0 && val
!= 1)
56 set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION
, &ctx
->flags
);
58 clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION
, &ctx
->flags
);
63 static int lowpan_ctx_flag_c_get(void *data
, u64
*val
)
65 *val
= lowpan_iphc_ctx_is_compression(data
);
69 DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops
, lowpan_ctx_flag_c_get
,
70 lowpan_ctx_flag_c_set
, "%llu\n");
72 static int lowpan_ctx_plen_set(void *data
, u64 val
)
74 struct lowpan_iphc_ctx
*ctx
= data
;
75 struct lowpan_iphc_ctx_table
*t
=
76 container_of(ctx
, struct lowpan_iphc_ctx_table
, table
[ctx
->id
]);
81 spin_lock_bh(&t
->lock
);
83 spin_unlock_bh(&t
->lock
);
88 static int lowpan_ctx_plen_get(void *data
, u64
*val
)
90 struct lowpan_iphc_ctx
*ctx
= data
;
91 struct lowpan_iphc_ctx_table
*t
=
92 container_of(ctx
, struct lowpan_iphc_ctx_table
, table
[ctx
->id
]);
94 spin_lock_bh(&t
->lock
);
96 spin_unlock_bh(&t
->lock
);
100 DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops
, lowpan_ctx_plen_get
,
101 lowpan_ctx_plen_set
, "%llu\n");
103 static int lowpan_ctx_pfx_show(struct seq_file
*file
, void *offset
)
105 struct lowpan_iphc_ctx
*ctx
= file
->private;
106 struct lowpan_iphc_ctx_table
*t
=
107 container_of(ctx
, struct lowpan_iphc_ctx_table
, table
[ctx
->id
]);
109 spin_lock_bh(&t
->lock
);
110 seq_printf(file
, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
111 be16_to_cpu(ctx
->pfx
.s6_addr16
[0]),
112 be16_to_cpu(ctx
->pfx
.s6_addr16
[1]),
113 be16_to_cpu(ctx
->pfx
.s6_addr16
[2]),
114 be16_to_cpu(ctx
->pfx
.s6_addr16
[3]),
115 be16_to_cpu(ctx
->pfx
.s6_addr16
[4]),
116 be16_to_cpu(ctx
->pfx
.s6_addr16
[5]),
117 be16_to_cpu(ctx
->pfx
.s6_addr16
[6]),
118 be16_to_cpu(ctx
->pfx
.s6_addr16
[7]));
119 spin_unlock_bh(&t
->lock
);
124 static int lowpan_ctx_pfx_open(struct inode
*inode
, struct file
*file
)
126 return single_open(file
, lowpan_ctx_pfx_show
, inode
->i_private
);
129 static ssize_t
lowpan_ctx_pfx_write(struct file
*fp
,
130 const char __user
*user_buf
, size_t count
,
134 struct seq_file
*file
= fp
->private_data
;
135 struct lowpan_iphc_ctx
*ctx
= file
->private;
136 struct lowpan_iphc_ctx_table
*t
=
137 container_of(ctx
, struct lowpan_iphc_ctx_table
, table
[ctx
->id
]);
138 int status
= count
, n
, i
;
139 unsigned int addr
[8];
141 if (copy_from_user(&buf
, user_buf
, min_t(size_t, sizeof(buf
) - 1,
147 n
= sscanf(buf
, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
148 &addr
[0], &addr
[1], &addr
[2], &addr
[3], &addr
[4],
149 &addr
[5], &addr
[6], &addr
[7]);
150 if (n
!= LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS
) {
155 spin_lock_bh(&t
->lock
);
156 for (i
= 0; i
< 8; i
++)
157 ctx
->pfx
.s6_addr16
[i
] = cpu_to_be16(addr
[i
] & 0xffff);
158 spin_unlock_bh(&t
->lock
);
164 static const struct file_operations lowpan_ctx_pfx_fops
= {
165 .open
= lowpan_ctx_pfx_open
,
167 .write
= lowpan_ctx_pfx_write
,
169 .release
= single_release
,
172 static int lowpan_dev_debugfs_ctx_init(struct net_device
*dev
,
173 struct dentry
*ctx
, u8 id
)
175 struct lowpan_dev
*ldev
= lowpan_dev(dev
);
176 struct dentry
*dentry
, *root
;
179 WARN_ON_ONCE(id
> LOWPAN_IPHC_CTX_TABLE_SIZE
);
181 sprintf(buf
, "%d", id
);
183 root
= debugfs_create_dir(buf
, ctx
);
187 dentry
= debugfs_create_file("active", 0644, root
,
188 &ldev
->ctx
.table
[id
],
189 &lowpan_ctx_flag_active_fops
);
193 dentry
= debugfs_create_file("compression", 0644, root
,
194 &ldev
->ctx
.table
[id
],
195 &lowpan_ctx_flag_c_fops
);
199 dentry
= debugfs_create_file("prefix", 0644, root
,
200 &ldev
->ctx
.table
[id
],
201 &lowpan_ctx_pfx_fops
);
205 dentry
= debugfs_create_file("prefix_len", 0644, root
,
206 &ldev
->ctx
.table
[id
],
207 &lowpan_ctx_plen_fops
);
214 static int lowpan_context_show(struct seq_file
*file
, void *offset
)
216 struct lowpan_iphc_ctx_table
*t
= file
->private;
219 seq_printf(file
, "%3s|%-43s|%c\n", "cid", "prefix", 'C');
220 seq_puts(file
, "-------------------------------------------------\n");
222 spin_lock_bh(&t
->lock
);
223 for (i
= 0; i
< LOWPAN_IPHC_CTX_TABLE_SIZE
; i
++) {
224 if (!lowpan_iphc_ctx_is_active(&t
->table
[i
]))
227 seq_printf(file
, "%3d|%39pI6c/%-3d|%d\n", t
->table
[i
].id
,
228 &t
->table
[i
].pfx
, t
->table
[i
].plen
,
229 lowpan_iphc_ctx_is_compression(&t
->table
[i
]));
231 spin_unlock_bh(&t
->lock
);
236 static int lowpan_context_open(struct inode
*inode
, struct file
*file
)
238 return single_open(file
, lowpan_context_show
, inode
->i_private
);
241 static const struct file_operations lowpan_context_fops
= {
242 .open
= lowpan_context_open
,
245 .release
= single_release
,
248 static int lowpan_short_addr_get(void *data
, u64
*val
)
250 struct wpan_dev
*wdev
= data
;
253 *val
= le16_to_cpu(wdev
->short_addr
);
259 DEFINE_SIMPLE_ATTRIBUTE(lowpan_short_addr_fops
, lowpan_short_addr_get
,
262 static int lowpan_dev_debugfs_802154_init(const struct net_device
*dev
,
263 struct lowpan_dev
*ldev
)
265 struct dentry
*dentry
, *root
;
267 if (!lowpan_is_ll(dev
, LOWPAN_LLTYPE_IEEE802154
))
270 root
= debugfs_create_dir("ieee802154", ldev
->iface_debugfs
);
274 dentry
= debugfs_create_file("short_addr", 0444, root
,
275 lowpan_802154_dev(dev
)->wdev
->ieee802154_ptr
,
276 &lowpan_short_addr_fops
);
283 int lowpan_dev_debugfs_init(struct net_device
*dev
)
285 struct lowpan_dev
*ldev
= lowpan_dev(dev
);
286 struct dentry
*contexts
, *dentry
;
289 /* creating the root */
290 ldev
->iface_debugfs
= debugfs_create_dir(dev
->name
, lowpan_debugfs
);
291 if (!ldev
->iface_debugfs
)
294 contexts
= debugfs_create_dir("contexts", ldev
->iface_debugfs
);
298 dentry
= debugfs_create_file("show", 0644, contexts
,
299 &lowpan_dev(dev
)->ctx
,
300 &lowpan_context_fops
);
304 for (i
= 0; i
< LOWPAN_IPHC_CTX_TABLE_SIZE
; i
++) {
305 ret
= lowpan_dev_debugfs_ctx_init(dev
, contexts
, i
);
310 ret
= lowpan_dev_debugfs_802154_init(dev
, ldev
);
317 lowpan_dev_debugfs_exit(dev
);
322 void lowpan_dev_debugfs_exit(struct net_device
*dev
)
324 debugfs_remove_recursive(lowpan_dev(dev
)->iface_debugfs
);
327 int __init
lowpan_debugfs_init(void)
329 lowpan_debugfs
= debugfs_create_dir("6lowpan", NULL
);
336 void lowpan_debugfs_exit(void)
338 debugfs_remove_recursive(lowpan_debugfs
);