linux/net/802/psnap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *      SNAP data link layer. Derived from 802.2
   4 *
   5 *              Alan Cox <alan@lxorguk.ukuu.org.uk>,
   6 *              from the 802.2 layer by Greg Page.
   7 *              Merged in additions from Greg Page's psnap.c.
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/netdevice.h>
  12#include <linux/skbuff.h>
  13#include <linux/slab.h>
  14#include <net/datalink.h>
  15#include <net/llc.h>
  16#include <net/psnap.h>
  17#include <linux/mm.h>
  18#include <linux/in.h>
  19#include <linux/init.h>
  20#include <linux/rculist.h>
  21
  22static LIST_HEAD(snap_list);
  23static DEFINE_SPINLOCK(snap_lock);
  24static struct llc_sap *snap_sap;
  25
  26/*
  27 *      Find a snap client by matching the 5 bytes.
  28 */
  29static struct datalink_proto *find_snap_client(const unsigned char *desc)
  30{
  31        struct datalink_proto *proto = NULL, *p;
  32
  33        list_for_each_entry_rcu(p, &snap_list, node, lockdep_is_held(&snap_lock)) {
  34                if (!memcmp(p->type, desc, 5)) {
  35                        proto = p;
  36                        break;
  37                }
  38        }
  39        return proto;
  40}
  41
  42/*
  43 *      A SNAP packet has arrived
  44 */
  45static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
  46                    struct packet_type *pt, struct net_device *orig_dev)
  47{
  48        int rc = 1;
  49        struct datalink_proto *proto;
  50        static struct packet_type snap_packet_type = {
  51                .type = cpu_to_be16(ETH_P_SNAP),
  52        };
  53
  54        if (unlikely(!pskb_may_pull(skb, 5)))
  55                goto drop;
  56
  57        rcu_read_lock();
  58        proto = find_snap_client(skb_transport_header(skb));
  59        if (proto) {
  60                /* Pass the frame on. */
  61                skb->transport_header += 5;
  62                skb_pull_rcsum(skb, 5);
  63                rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
  64        }
  65        rcu_read_unlock();
  66
  67        if (unlikely(!proto))
  68                goto drop;
  69
  70out:
  71        return rc;
  72
  73drop:
  74        kfree_skb(skb);
  75        goto out;
  76}
  77
  78/*
  79 *      Put a SNAP header on a frame and pass to 802.2
  80 */
  81static int snap_request(struct datalink_proto *dl,
  82                        struct sk_buff *skb, const u8 *dest)
  83{
  84        memcpy(skb_push(skb, 5), dl->type, 5);
  85        llc_build_and_send_ui_pkt(snap_sap, skb, dest, snap_sap->laddr.lsap);
  86        return 0;
  87}
  88
  89/*
  90 *      Set up the SNAP layer
  91 */
  92EXPORT_SYMBOL(register_snap_client);
  93EXPORT_SYMBOL(unregister_snap_client);
  94
  95static const char snap_err_msg[] __initconst =
  96        KERN_CRIT "SNAP - unable to register with 802.2\n";
  97
  98static int __init snap_init(void)
  99{
 100        snap_sap = llc_sap_open(0xAA, snap_rcv);
 101        if (!snap_sap) {
 102                printk(snap_err_msg);
 103                return -EBUSY;
 104        }
 105
 106        return 0;
 107}
 108
 109module_init(snap_init);
 110
 111static void __exit snap_exit(void)
 112{
 113        llc_sap_put(snap_sap);
 114}
 115
 116module_exit(snap_exit);
 117
 118
 119/*
 120 *      Register SNAP clients. We don't yet use this for IP.
 121 */
 122struct datalink_proto *register_snap_client(const unsigned char *desc,
 123                                            int (*rcvfunc)(struct sk_buff *,
 124                                                           struct net_device *,
 125                                                           struct packet_type *,
 126                                                           struct net_device *))
 127{
 128        struct datalink_proto *proto = NULL;
 129
 130        spin_lock_bh(&snap_lock);
 131
 132        if (find_snap_client(desc))
 133                goto out;
 134
 135        proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
 136        if (proto) {
 137                memcpy(proto->type, desc, 5);
 138                proto->rcvfunc          = rcvfunc;
 139                proto->header_length    = 5 + 3; /* snap + 802.2 */
 140                proto->request          = snap_request;
 141                list_add_rcu(&proto->node, &snap_list);
 142        }
 143out:
 144        spin_unlock_bh(&snap_lock);
 145
 146        return proto;
 147}
 148
 149/*
 150 *      Unregister SNAP clients. Protocols no longer want to play with us ...
 151 */
 152void unregister_snap_client(struct datalink_proto *proto)
 153{
 154        spin_lock_bh(&snap_lock);
 155        list_del_rcu(&proto->node);
 156        spin_unlock_bh(&snap_lock);
 157
 158        synchronize_net();
 159
 160        kfree(proto);
 161}
 162
 163MODULE_LICENSE("GPL");
 164