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