linux/net/rose/rose_loopback.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *
   4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   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/rose.h>
  13#include <linux/init.h>
  14
  15static struct sk_buff_head loopback_queue;
  16#define ROSE_LOOPBACK_LIMIT 1000
  17static struct timer_list loopback_timer;
  18
  19static void rose_set_loopback_timer(void);
  20static void rose_loopback_timer(struct timer_list *unused);
  21
  22void rose_loopback_init(void)
  23{
  24        skb_queue_head_init(&loopback_queue);
  25
  26        timer_setup(&loopback_timer, rose_loopback_timer, 0);
  27}
  28
  29static int rose_loopback_running(void)
  30{
  31        return timer_pending(&loopback_timer);
  32}
  33
  34int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
  35{
  36        struct sk_buff *skbn = NULL;
  37
  38        if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT)
  39                skbn = skb_clone(skb, GFP_ATOMIC);
  40
  41        if (skbn) {
  42                consume_skb(skb);
  43                skb_queue_tail(&loopback_queue, skbn);
  44
  45                if (!rose_loopback_running())
  46                        rose_set_loopback_timer();
  47        } else {
  48                kfree_skb(skb);
  49        }
  50
  51        return 1;
  52}
  53
  54static void rose_set_loopback_timer(void)
  55{
  56        mod_timer(&loopback_timer, jiffies + 10);
  57}
  58
  59static void rose_loopback_timer(struct timer_list *unused)
  60{
  61        struct sk_buff *skb;
  62        struct net_device *dev;
  63        rose_address *dest;
  64        struct sock *sk;
  65        unsigned short frametype;
  66        unsigned int lci_i, lci_o;
  67        int count;
  68
  69        for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) {
  70                skb = skb_dequeue(&loopback_queue);
  71                if (!skb)
  72                        return;
  73                if (skb->len < ROSE_MIN_LEN) {
  74                        kfree_skb(skb);
  75                        continue;
  76                }
  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)) {
  83                        kfree_skb(skb);
  84                        continue;
  85                }
  86                dest      = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF);
  87                lci_o     = ROSE_DEFAULT_MAXVC + 1 - lci_i;
  88
  89                skb_reset_transport_header(skb);
  90
  91                sk = rose_find_socket(lci_o, rose_loopback_neigh);
  92                if (sk) {
  93                        if (rose_process_rx_frame(sk, skb) == 0)
  94                                kfree_skb(skb);
  95                        continue;
  96                }
  97
  98                if (frametype == ROSE_CALL_REQUEST) {
  99                        if (!rose_loopback_neigh->dev) {
 100                                kfree_skb(skb);
 101                                continue;
 102                        }
 103
 104                        dev = rose_dev_get(dest);
 105                        if (!dev) {
 106                                kfree_skb(skb);
 107                                continue;
 108                        }
 109
 110                        if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) {
 111                                dev_put(dev);
 112                                kfree_skb(skb);
 113                        }
 114                } else {
 115                        kfree_skb(skb);
 116                }
 117        }
 118        if (!skb_queue_empty(&loopback_queue))
 119                mod_timer(&loopback_timer, jiffies + 1);
 120}
 121
 122void __exit rose_loopback_clear(void)
 123{
 124        struct sk_buff *skb;
 125
 126        del_timer(&loopback_timer);
 127
 128        while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
 129                skb->sk = NULL;
 130                kfree_skb(skb);
 131        }
 132}
 133