diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 8ddc2ab23142..3af0bdc86491 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2216,6 +2216,135 @@ static const struct file_operations softnet_seq_fops = { | |||
2216 | .release = seq_release, | 2216 | .release = seq_release, |
2217 | }; | 2217 | }; |
2218 | 2218 | ||
2219 | static void *ptype_get_idx(loff_t pos) | ||
2220 | { | ||
2221 | struct packet_type *pt = NULL; | ||
2222 | loff_t i = 0; | ||
2223 | int t; | ||
2224 | |||
2225 | list_for_each_entry_rcu(pt, &ptype_all, list) { | ||
2226 | if (i == pos) | ||
2227 | return pt; | ||
2228 | ++i; | ||
2229 | } | ||
2230 | |||
2231 | for (t = 0; t < 16; t++) { | ||
2232 | list_for_each_entry_rcu(pt, &ptype_base[t], list) { | ||
2233 | if (i == pos) | ||
2234 | return pt; | ||
2235 | ++i; | ||
2236 | } | ||
2237 | } | ||
2238 | return NULL; | ||
2239 | } | ||
2240 | |||
2241 | static void *ptype_seq_start(struct seq_file *seq, loff_t *pos) | ||
2242 | { | ||
2243 | rcu_read_lock(); | ||
2244 | return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN; | ||
2245 | } | ||
2246 | |||
2247 | static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
2248 | { | ||
2249 | struct packet_type *pt; | ||
2250 | struct list_head *nxt; | ||
2251 | int hash; | ||
2252 | |||
2253 | ++*pos; | ||
2254 | if (v == SEQ_START_TOKEN) | ||
2255 | return ptype_get_idx(0); | ||
2256 | |||
2257 | pt = v; | ||
2258 | nxt = pt->list.next; | ||
2259 | if (pt->type == htons(ETH_P_ALL)) { | ||
2260 | if (nxt != &ptype_all) | ||
2261 | goto found; | ||
2262 | hash = 0; | ||
2263 | nxt = ptype_base[0].next; | ||
2264 | } else | ||
2265 | hash = ntohs(pt->type) & 15; | ||
2266 | |||
2267 | while (nxt == &ptype_base[hash]) { | ||
2268 | if (++hash >= 16) | ||
2269 | return NULL; | ||
2270 | nxt = ptype_base[hash].next; | ||
2271 | } | ||
2272 | found: | ||
2273 | return list_entry(nxt, struct packet_type, list); | ||
2274 | } | ||
2275 | |||
2276 | static void ptype_seq_stop(struct seq_file *seq, void *v) | ||
2277 | { | ||
2278 | rcu_read_unlock(); | ||
2279 | } | ||
2280 | |||
2281 | static void ptype_seq_decode(struct seq_file *seq, void *sym) | ||
2282 | { | ||
2283 | #ifdef CONFIG_KALLSYMS | ||
2284 | unsigned long offset = 0, symsize; | ||
2285 | const char *symname; | ||
2286 | char *modname; | ||
2287 | char namebuf[128]; | ||
2288 | |||
2289 | symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset, | ||
2290 | &modname, namebuf); | ||
2291 | |||
2292 | if (symname) { | ||
2293 | char *delim = ":"; | ||
2294 | |||
2295 | if (!modname) | ||
2296 | modname = delim = ""; | ||
2297 | seq_printf(seq, "%s%s%s%s+0x%lx", delim, modname, delim, | ||
2298 | symname, offset); | ||
2299 | return; | ||
2300 | } | ||
2301 | #endif | ||
2302 | |||
2303 | seq_printf(seq, "[%p]", sym); | ||
2304 | } | ||
2305 | |||
2306 | static int ptype_seq_show(struct seq_file *seq, void *v) | ||
2307 | { | ||
2308 | struct packet_type *pt = v; | ||
2309 | |||
2310 | if (v == SEQ_START_TOKEN) | ||
2311 | seq_puts(seq, "Type Device Function\n"); | ||
2312 | else { | ||
2313 | if (pt->type == htons(ETH_P_ALL)) | ||
2314 | seq_puts(seq, "ALL "); | ||
2315 | else | ||
2316 | seq_printf(seq, "%04x", ntohs(pt->type)); | ||
2317 | |||
2318 | seq_printf(seq, " %-8s ", | ||
2319 | pt->dev ? pt->dev->name : ""); | ||
2320 | ptype_seq_decode(seq, pt->func); | ||
2321 | seq_putc(seq, '\n'); | ||
2322 | } | ||
2323 | |||
2324 | return 0; | ||
2325 | } | ||
2326 | |||
2327 | static const struct seq_operations ptype_seq_ops = { | ||
2328 | .start = ptype_seq_start, | ||
2329 | .next = ptype_seq_next, | ||
2330 | .stop = ptype_seq_stop, | ||
2331 | .show = ptype_seq_show, | ||
2332 | }; | ||
2333 | |||
2334 | static int ptype_seq_open(struct inode *inode, struct file *file) | ||
2335 | { | ||
2336 | return seq_open(file, &ptype_seq_ops); | ||
2337 | } | ||
2338 | |||
2339 | static const struct file_operations ptype_seq_fops = { | ||
2340 | .owner = THIS_MODULE, | ||
2341 | .open = ptype_seq_open, | ||
2342 | .read = seq_read, | ||
2343 | .llseek = seq_lseek, | ||
2344 | .release = seq_release, | ||
2345 | }; | ||
2346 | |||
2347 | |||
2219 | #ifdef CONFIG_WIRELESS_EXT | 2348 | #ifdef CONFIG_WIRELESS_EXT |
2220 | extern int wireless_proc_init(void); | 2349 | extern int wireless_proc_init(void); |
2221 | #else | 2350 | #else |
@@ -2230,6 +2359,9 @@ static int __init dev_proc_init(void) | |||
2230 | goto out; | 2359 | goto out; |
2231 | if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops)) | 2360 | if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops)) |
2232 | goto out_dev; | 2361 | goto out_dev; |
2362 | if (!proc_net_fops_create("ptype", S_IRUGO, &ptype_seq_fops)) | ||
2363 | goto out_dev2; | ||
2364 | |||
2233 | if (wireless_proc_init()) | 2365 | if (wireless_proc_init()) |
2234 | goto out_softnet; | 2366 | goto out_softnet; |
2235 | rc = 0; | 2367 | rc = 0; |
@@ -2237,6 +2369,8 @@ out: | |||
2237 | return rc; | 2369 | return rc; |
2238 | out_softnet: | 2370 | out_softnet: |
2239 | proc_net_remove("softnet_stat"); | 2371 | proc_net_remove("softnet_stat"); |
2372 | out_dev2: | ||
2373 | proc_net_remove("ptype"); | ||
2240 | out_dev: | 2374 | out_dev: |
2241 | proc_net_remove("dev"); | 2375 | proc_net_remove("dev"); |
2242 | goto out; | 2376 | goto out; |