1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
6 #include <linux/types.h>
7 #include <linux/slab.h>
8 #include <linux/socket.h>
9 #include <linux/timer.h>
11 #include <linux/skbuff.h>
13 #include <linux/init.h>
15 static struct sk_buff_head loopback_queue
;
16 #define ROSE_LOOPBACK_LIMIT 1000
17 static struct timer_list loopback_timer
;
19 static void rose_set_loopback_timer(void);
20 static void rose_loopback_timer(struct timer_list
*unused
);
22 void rose_loopback_init(void)
24 skb_queue_head_init(&loopback_queue
);
26 timer_setup(&loopback_timer
, rose_loopback_timer
, 0);
29 static int rose_loopback_running(void)
31 return timer_pending(&loopback_timer
);
34 int rose_loopback_queue(struct sk_buff
*skb
, struct rose_neigh
*neigh
)
36 struct sk_buff
*skbn
= NULL
;
38 if (skb_queue_len(&loopback_queue
) < ROSE_LOOPBACK_LIMIT
)
39 skbn
= skb_clone(skb
, GFP_ATOMIC
);
43 skb_queue_tail(&loopback_queue
, skbn
);
45 if (!rose_loopback_running())
46 rose_set_loopback_timer();
54 static void rose_set_loopback_timer(void)
56 mod_timer(&loopback_timer
, jiffies
+ 10);
59 static void rose_loopback_timer(struct timer_list
*unused
)
62 struct net_device
*dev
;
65 unsigned short frametype
;
66 unsigned int lci_i
, lci_o
;
69 for (count
= 0; count
< ROSE_LOOPBACK_LIMIT
; count
++) {
70 skb
= skb_dequeue(&loopback_queue
);
73 if (skb
->len
< ROSE_MIN_LEN
) {
77 lci_i
= ((skb
->data
[0] << 8) & 0xF00) + ((skb
->data
[1] << 0) & 0x0FF);
78 frametype
= skb
->data
[2];
79 if (frametype
== ROSE_CALL_REQUEST
&&
80 (skb
->len
<= ROSE_CALL_REQ_FACILITIES_OFF
||
81 skb
->data
[ROSE_CALL_REQ_ADDR_LEN_OFF
] !=
82 ROSE_CALL_REQ_ADDR_LEN_VAL
)) {
86 dest
= (rose_address
*)(skb
->data
+ ROSE_CALL_REQ_DEST_ADDR_OFF
);
87 lci_o
= ROSE_DEFAULT_MAXVC
+ 1 - lci_i
;
89 skb_reset_transport_header(skb
);
91 sk
= rose_find_socket(lci_o
, rose_loopback_neigh
);
93 if (rose_process_rx_frame(sk
, skb
) == 0)
98 if (frametype
== ROSE_CALL_REQUEST
) {
99 if ((dev
= rose_dev_get(dest
)) != NULL
) {
100 if (rose_rx_call_request(skb
, dev
, rose_loopback_neigh
, lci_o
) == 0)
109 if (!skb_queue_empty(&loopback_queue
))
110 mod_timer(&loopback_timer
, jiffies
+ 1);
113 void __exit
rose_loopback_clear(void)
117 del_timer(&loopback_timer
);
119 while ((skb
= skb_dequeue(&loopback_queue
)) != NULL
) {