162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/socket.h> 962306a36Sopenharmony_ci#include <linux/timer.h> 1062306a36Sopenharmony_ci#include <net/ax25.h> 1162306a36Sopenharmony_ci#include <linux/skbuff.h> 1262306a36Sopenharmony_ci#include <net/rose.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic struct sk_buff_head loopback_queue; 1662306a36Sopenharmony_ci#define ROSE_LOOPBACK_LIMIT 1000 1762306a36Sopenharmony_cistatic struct timer_list loopback_timer; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void rose_set_loopback_timer(void); 2062306a36Sopenharmony_cistatic void rose_loopback_timer(struct timer_list *unused); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid rose_loopback_init(void) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci skb_queue_head_init(&loopback_queue); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci timer_setup(&loopback_timer, rose_loopback_timer, 0); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int rose_loopback_running(void) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci return timer_pending(&loopback_timer); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciint rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct sk_buff *skbn = NULL; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT) 3962306a36Sopenharmony_ci skbn = skb_clone(skb, GFP_ATOMIC); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (skbn) { 4262306a36Sopenharmony_ci consume_skb(skb); 4362306a36Sopenharmony_ci skb_queue_tail(&loopback_queue, skbn); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (!rose_loopback_running()) 4662306a36Sopenharmony_ci rose_set_loopback_timer(); 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci kfree_skb(skb); 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 1; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void rose_set_loopback_timer(void) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci mod_timer(&loopback_timer, jiffies + 10); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void rose_loopback_timer(struct timer_list *unused) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct sk_buff *skb; 6262306a36Sopenharmony_ci struct net_device *dev; 6362306a36Sopenharmony_ci rose_address *dest; 6462306a36Sopenharmony_ci struct sock *sk; 6562306a36Sopenharmony_ci unsigned short frametype; 6662306a36Sopenharmony_ci unsigned int lci_i, lci_o; 6762306a36Sopenharmony_ci int count; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) { 7062306a36Sopenharmony_ci skb = skb_dequeue(&loopback_queue); 7162306a36Sopenharmony_ci if (!skb) 7262306a36Sopenharmony_ci return; 7362306a36Sopenharmony_ci if (skb->len < ROSE_MIN_LEN) { 7462306a36Sopenharmony_ci kfree_skb(skb); 7562306a36Sopenharmony_ci continue; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 7862306a36Sopenharmony_ci frametype = skb->data[2]; 7962306a36Sopenharmony_ci if (frametype == ROSE_CALL_REQUEST && 8062306a36Sopenharmony_ci (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || 8162306a36Sopenharmony_ci skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != 8262306a36Sopenharmony_ci ROSE_CALL_REQ_ADDR_LEN_VAL)) { 8362306a36Sopenharmony_ci kfree_skb(skb); 8462306a36Sopenharmony_ci continue; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); 8762306a36Sopenharmony_ci lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci skb_reset_transport_header(skb); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci sk = rose_find_socket(lci_o, rose_loopback_neigh); 9262306a36Sopenharmony_ci if (sk) { 9362306a36Sopenharmony_ci if (rose_process_rx_frame(sk, skb) == 0) 9462306a36Sopenharmony_ci kfree_skb(skb); 9562306a36Sopenharmony_ci continue; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (frametype == ROSE_CALL_REQUEST) { 9962306a36Sopenharmony_ci if (!rose_loopback_neigh->dev && 10062306a36Sopenharmony_ci !rose_loopback_neigh->loopback) { 10162306a36Sopenharmony_ci kfree_skb(skb); 10262306a36Sopenharmony_ci continue; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci dev = rose_dev_get(dest); 10662306a36Sopenharmony_ci if (!dev) { 10762306a36Sopenharmony_ci kfree_skb(skb); 10862306a36Sopenharmony_ci continue; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) { 11262306a36Sopenharmony_ci dev_put(dev); 11362306a36Sopenharmony_ci kfree_skb(skb); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci } else { 11662306a36Sopenharmony_ci kfree_skb(skb); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci if (!skb_queue_empty(&loopback_queue)) 12062306a36Sopenharmony_ci mod_timer(&loopback_timer, jiffies + 1); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_civoid __exit rose_loopback_clear(void) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct sk_buff *skb; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci del_timer(&loopback_timer); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci while ((skb = skb_dequeue(&loopback_queue)) != NULL) { 13062306a36Sopenharmony_ci skb->sk = NULL; 13162306a36Sopenharmony_ci kfree_skb(skb); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 134