]> err.no Git - linux-2.6/blobdiff - drivers/net/wan/hdlc.c
tty: Ldisc revamp
[linux-2.6] / drivers / net / wan / hdlc.c
index 9040d7cf651e585d6b3976b76159ddef7125c7ee..7f984895b0d53efbcada5adaf6f8a625dc9be9f0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
 #include <linux/rtnetlink.h>
 #include <linux/notifier.h>
 #include <linux/hdlc.h>
+#include <net/net_namespace.h>
 
 
-static const char* version = "HDLC support module revision 1.20";
+static const char* version = "HDLC support module revision 1.22";
 
 #undef DEBUG_LINK
 
-static struct hdlc_proto *first_proto = NULL;
-
+static struct hdlc_proto *first_proto;
 
 static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
 {
@@ -65,13 +65,15 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *p, struct net_device *orig_dev)
 {
-       struct hdlc_device_desc *desc = dev_to_desc(dev);
-       if (desc->netif_rx)
-               return desc->netif_rx(skb);
+       struct hdlc_device *hdlc = dev_to_hdlc(dev);
+
+       if (dev_net(dev) != &init_net) {
+               kfree_skb(skb);
+               return 0;
+       }
 
-       desc->stats.rx_dropped++; /* Shouldn't happen */
-       dev_kfree_skb(skb);
-       return NET_RX_DROP;
+       BUG_ON(!hdlc->proto->netif_rx);
+       return hdlc->proto->netif_rx(skb);
 }
 
 
@@ -80,7 +82,7 @@ static inline void hdlc_proto_start(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->start)
-               return hdlc->proto->start(dev);
+               hdlc->proto->start(dev);
 }
 
 
@@ -89,7 +91,7 @@ static inline void hdlc_proto_stop(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->stop)
-               return hdlc->proto->stop(dev);
+               hdlc->proto->stop(dev);
 }
 
 
@@ -102,6 +104,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event,
        unsigned long flags;
        int on;
  
+       if (dev_net(dev) != &init_net)
+               return NOTIFY_DONE;
+
        if (dev->get_stats != hdlc_get_stats)
                return NOTIFY_DONE; /* not an HDLC device */
  
@@ -222,19 +227,29 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EINVAL;
 }
 
+static const struct header_ops hdlc_null_ops;
+
+static void hdlc_setup_dev(struct net_device *dev)
+{
+       /* Re-init all variables changed by HDLC protocol drivers,
+        * including ether_setup() called from hdlc_raw_eth.c.
+        */
+       dev->get_stats           = hdlc_get_stats;
+       dev->flags               = IFF_POINTOPOINT | IFF_NOARP;
+       dev->mtu                 = HDLC_MAX_MTU;
+       dev->type                = ARPHRD_RAWHDLC;
+       dev->hard_header_len     = 16;
+       dev->addr_len            = 0;
+       dev->header_ops          = &hdlc_null_ops;
+
+       dev->change_mtu          = hdlc_change_mtu;
+}
+
 static void hdlc_setup(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
 
-       dev->get_stats = hdlc_get_stats;
-       dev->change_mtu = hdlc_change_mtu;
-       dev->mtu = HDLC_MAX_MTU;
-
-       dev->type = ARPHRD_RAWHDLC;
-       dev->hard_header_len = 16;
-
-       dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
+       hdlc_setup_dev(dev);
        hdlc->carrier = 1;
        hdlc->open = 0;
        spin_lock_init(&hdlc->state_lock);
@@ -243,8 +258,7 @@ static void hdlc_setup(struct net_device *dev)
 struct net_device *alloc_hdlcdev(void *priv)
 {
        struct net_device *dev;
-       dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
-                          sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+       dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup);
        if (dev)
                dev_to_hdlc(dev)->priv = priv;
        return dev;
@@ -261,7 +275,7 @@ void unregister_hdlc_device(struct net_device *dev)
 
 
 int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
-                        int (*rx)(struct sk_buff *skb), size_t size)
+                        size_t size)
 {
        detach_hdlc_protocol(dev);
 
@@ -277,7 +291,6 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
                        return -ENOBUFS;
                }
        dev_to_hdlc(dev)->proto = proto;
-       dev_to_desc(dev)->netif_rx = rx;
        return 0;
 }
 
@@ -294,26 +307,31 @@ void detach_hdlc_protocol(struct net_device *dev)
        }
        kfree(hdlc->state);
        hdlc->state = NULL;
+       hdlc_setup_dev(dev);
 }
 
 
 void register_hdlc_protocol(struct hdlc_proto *proto)
 {
+       rtnl_lock();
        proto->next = first_proto;
        first_proto = proto;
+       rtnl_unlock();
 }
 
 
 void unregister_hdlc_protocol(struct hdlc_proto *proto)
 {
-       struct hdlc_proto **p = &first_proto;
-       while (*p) {
-               if (*p == proto) {
-                       *p = proto->next;
-                       return;
-               }
+       struct hdlc_proto **p;
+
+       rtnl_lock();
+       p = &first_proto;
+       while (*p != proto) {
+               BUG_ON(!*p);
                p = &((*p)->next);
        }
+       *p = proto->next;
+       rtnl_unlock();
 }