1 | // SPDX-License-Identifier: GPL-2.0-or-later |
---|---|
2 | /* |
3 | * |
4 | * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi) |
5 | */ |
6 | #include <linux/types.h> |
7 | #include <linux/slab.h> |
8 | #include <linux/socket.h> |
9 | #include <linux/timer.h> |
10 | #include <net/ax25.h> |
11 | #include <linux/skbuff.h> |
12 | #include <net/netrom.h> |
13 | #include <linux/init.h> |
14 | |
15 | static void nr_loopback_timer(struct timer_list *); |
16 | |
17 | static struct sk_buff_head loopback_queue; |
18 | static DEFINE_TIMER(loopback_timer, nr_loopback_timer); |
19 | |
20 | void __init nr_loopback_init(void) |
21 | { |
22 | skb_queue_head_init(list: &loopback_queue); |
23 | } |
24 | |
25 | static inline int nr_loopback_running(void) |
26 | { |
27 | return timer_pending(timer: &loopback_timer); |
28 | } |
29 | |
30 | int nr_loopback_queue(struct sk_buff *skb) |
31 | { |
32 | struct sk_buff *skbn; |
33 | |
34 | if ((skbn = alloc_skb(size: skb->len, GFP_ATOMIC)) != NULL) { |
35 | skb_copy_from_linear_data(skb, to: skb_put(skb: skbn, len: skb->len), len: skb->len); |
36 | skb_reset_transport_header(skb: skbn); |
37 | |
38 | skb_queue_tail(list: &loopback_queue, newsk: skbn); |
39 | |
40 | if (!nr_loopback_running()) |
41 | mod_timer(timer: &loopback_timer, expires: jiffies + 10); |
42 | } |
43 | |
44 | kfree_skb(skb); |
45 | return 1; |
46 | } |
47 | |
48 | static void nr_loopback_timer(struct timer_list *unused) |
49 | { |
50 | struct sk_buff *skb; |
51 | ax25_address *nr_dest; |
52 | struct net_device *dev; |
53 | |
54 | if ((skb = skb_dequeue(list: &loopback_queue)) != NULL) { |
55 | nr_dest = (ax25_address *)(skb->data + 7); |
56 | |
57 | dev = nr_dev_get(nr_dest); |
58 | |
59 | if (dev == NULL || nr_rx_frame(skb, dev) == 0) |
60 | kfree_skb(skb); |
61 | |
62 | dev_put(dev); |
63 | |
64 | if (!skb_queue_empty(list: &loopback_queue) && !nr_loopback_running()) |
65 | mod_timer(timer: &loopback_timer, expires: jiffies + 10); |
66 | } |
67 | } |
68 | |
69 | void nr_loopback_clear(void) |
70 | { |
71 | del_timer_sync(timer: &loopback_timer); |
72 | skb_queue_purge(list: &loopback_queue); |
73 | } |
74 |