18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/socket.h> 98c2ecf20Sopenharmony_ci#include <linux/timer.h> 108c2ecf20Sopenharmony_ci#include <net/ax25.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <net/rose.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct sk_buff_head loopback_queue; 168c2ecf20Sopenharmony_ci#define ROSE_LOOPBACK_LIMIT 1000 178c2ecf20Sopenharmony_cistatic struct timer_list loopback_timer; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic void rose_set_loopback_timer(void); 208c2ecf20Sopenharmony_cistatic void rose_loopback_timer(struct timer_list *unused); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid rose_loopback_init(void) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci skb_queue_head_init(&loopback_queue); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci timer_setup(&loopback_timer, rose_loopback_timer, 0); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int rose_loopback_running(void) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci return timer_pending(&loopback_timer); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciint rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct sk_buff *skbn = NULL; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT) 398c2ecf20Sopenharmony_ci skbn = skb_clone(skb, GFP_ATOMIC); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (skbn) { 428c2ecf20Sopenharmony_ci consume_skb(skb); 438c2ecf20Sopenharmony_ci skb_queue_tail(&loopback_queue, skbn); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!rose_loopback_running()) 468c2ecf20Sopenharmony_ci rose_set_loopback_timer(); 478c2ecf20Sopenharmony_ci } else { 488c2ecf20Sopenharmony_ci kfree_skb(skb); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return 1; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void rose_set_loopback_timer(void) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci mod_timer(&loopback_timer, jiffies + 10); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void rose_loopback_timer(struct timer_list *unused) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct sk_buff *skb; 628c2ecf20Sopenharmony_ci struct net_device *dev; 638c2ecf20Sopenharmony_ci rose_address *dest; 648c2ecf20Sopenharmony_ci struct sock *sk; 658c2ecf20Sopenharmony_ci unsigned short frametype; 668c2ecf20Sopenharmony_ci unsigned int lci_i, lci_o; 678c2ecf20Sopenharmony_ci int count; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) { 708c2ecf20Sopenharmony_ci skb = skb_dequeue(&loopback_queue); 718c2ecf20Sopenharmony_ci if (!skb) 728c2ecf20Sopenharmony_ci return; 738c2ecf20Sopenharmony_ci if (skb->len < ROSE_MIN_LEN) { 748c2ecf20Sopenharmony_ci kfree_skb(skb); 758c2ecf20Sopenharmony_ci continue; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 788c2ecf20Sopenharmony_ci frametype = skb->data[2]; 798c2ecf20Sopenharmony_ci if (frametype == ROSE_CALL_REQUEST && 808c2ecf20Sopenharmony_ci (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || 818c2ecf20Sopenharmony_ci skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != 828c2ecf20Sopenharmony_ci ROSE_CALL_REQ_ADDR_LEN_VAL)) { 838c2ecf20Sopenharmony_ci kfree_skb(skb); 848c2ecf20Sopenharmony_ci continue; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); 878c2ecf20Sopenharmony_ci lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci sk = rose_find_socket(lci_o, rose_loopback_neigh); 928c2ecf20Sopenharmony_ci if (sk) { 938c2ecf20Sopenharmony_ci if (rose_process_rx_frame(sk, skb) == 0) 948c2ecf20Sopenharmony_ci kfree_skb(skb); 958c2ecf20Sopenharmony_ci continue; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (frametype == ROSE_CALL_REQUEST) { 998c2ecf20Sopenharmony_ci if (!rose_loopback_neigh->dev && 1008c2ecf20Sopenharmony_ci !rose_loopback_neigh->loopback) { 1018c2ecf20Sopenharmony_ci kfree_skb(skb); 1028c2ecf20Sopenharmony_ci continue; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci dev = rose_dev_get(dest); 1068c2ecf20Sopenharmony_ci if (!dev) { 1078c2ecf20Sopenharmony_ci kfree_skb(skb); 1088c2ecf20Sopenharmony_ci continue; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) { 1128c2ecf20Sopenharmony_ci dev_put(dev); 1138c2ecf20Sopenharmony_ci kfree_skb(skb); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci kfree_skb(skb); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci if (!skb_queue_empty(&loopback_queue)) 1208c2ecf20Sopenharmony_ci mod_timer(&loopback_timer, jiffies + 1); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid __exit rose_loopback_clear(void) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct sk_buff *skb; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci del_timer(&loopback_timer); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&loopback_queue)) != NULL) { 1308c2ecf20Sopenharmony_ci skb->sk = NULL; 1318c2ecf20Sopenharmony_ci kfree_skb(skb); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci} 134