From: Krzysztof Halasa <khc@pm.waw.pl>

The following patch upgrades generic HDLC to support "new" protocol
handlers.



 25-akpm/drivers/net/wan/hdlc_cisco.c   |   19 +++++++++----------
 25-akpm/drivers/net/wan/hdlc_fr.c      |   23 +++++++++++++++--------
 25-akpm/drivers/net/wan/hdlc_generic.c |   16 ++++++++--------
 25-akpm/drivers/net/wan/hdlc_x25.c     |   11 +++++++++--
 25-akpm/include/linux/hdlc.h           |    2 +-
 5 files changed, 42 insertions(+), 29 deletions(-)

diff -puN drivers/net/wan/hdlc_cisco.c~generic-hdlc-updates drivers/net/wan/hdlc_cisco.c
--- 25/drivers/net/wan/hdlc_cisco.c~generic-hdlc-updates	Tue Jul 29 14:31:55 2003
+++ 25-akpm/drivers/net/wan/hdlc_cisco.c	Tue Jul 29 14:31:55 2003
@@ -116,7 +116,7 @@ static unsigned short cisco_type_trans(s
 }
 
 
-static void cisco_rx(struct sk_buff *skb)
+static int cisco_rx(struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 	hdlc_header *data = (hdlc_header*)skb->data;
@@ -131,24 +131,22 @@ static void cisco_rx(struct sk_buff *skb
 	    data->address != CISCO_UNICAST)
 		goto rx_error;
 
-	skb_pull(skb, sizeof(hdlc_header));
-
 	switch(ntohs(data->protocol)) {
 	case CISCO_SYS_INFO:
 		/* Packet is not needed, drop it. */
 		dev_kfree_skb_any(skb);
-		return;
+		return NET_RX_SUCCESS;
 
 	case CISCO_KEEPALIVE:
-		if (skb->len != CISCO_PACKET_LEN &&
-		    skb->len != CISCO_BIG_PACKET_LEN) {
+		if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
+		    skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
 			printk(KERN_INFO "%s: Invalid length of Cisco "
 			       "control packet (%d bytes)\n",
 			       hdlc_to_name(hdlc), skb->len);
 			goto rx_error;
 		}
 
-		cisco_data = (cisco_packet*)skb->data;
+		cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
 
 		switch(ntohl (cisco_data->type)) {
 		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
@@ -173,7 +171,7 @@ static void cisco_rx(struct sk_buff *skb
 						     addr, mask);
 			}
 			dev_kfree_skb_any(skb);
-			return;
+			return NET_RX_SUCCESS;
 
 		case CISCO_ADDR_REPLY:
 			printk(KERN_INFO "%s: Unexpected Cisco IP address "
@@ -199,18 +197,19 @@ static void cisco_rx(struct sk_buff *skb
 			}
 
 			dev_kfree_skb_any(skb);
-			return;
+			return NET_RX_SUCCESS;
 		} /* switch(keepalive type) */
 	} /* switch(protocol) */
 
 	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
 	       data->protocol);
 	dev_kfree_skb_any(skb);
-	return;
+	return NET_RX_DROP;
 
  rx_error:
 	hdlc->stats.rx_errors++; /* Mark error */
 	dev_kfree_skb_any(skb);
+	return NET_RX_DROP;
 }
 
 
diff -puN drivers/net/wan/hdlc_fr.c~generic-hdlc-updates drivers/net/wan/hdlc_fr.c
--- 25/drivers/net/wan/hdlc_fr.c~generic-hdlc-updates	Tue Jul 29 14:31:55 2003
+++ 25-akpm/drivers/net/wan/hdlc_fr.c	Tue Jul 29 14:31:55 2003
@@ -800,7 +800,7 @@ static int fr_lmi_recv(hdlc_device *hdlc
 
 
 
-static void fr_rx(struct sk_buff *skb)
+static int fr_rx(struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 	fr_hdr *fh = (fr_hdr*)skb->data;
@@ -826,7 +826,7 @@ static void fr_rx(struct sk_buff *skb)
 				hdlc->state.fr.request = 0;
 				hdlc->state.fr.last_poll = jiffies;
 				dev_kfree_skb_any(skb);
-				return;
+				return NET_RX_SUCCESS;
 			}
 		}
 
@@ -842,7 +842,7 @@ static void fr_rx(struct sk_buff *skb)
 		       hdlc_to_name(hdlc), dlci);
 #endif
 		dev_kfree_skb_any(skb);
-		return;
+		return NET_RX_DROP;
 	}
 
 	if (pvc->state.fecn != fh->fecn) {
@@ -862,6 +862,11 @@ static void fr_rx(struct sk_buff *skb)
 	}
 
 
+	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+		hdlc->stats.rx_dropped++;
+		return NET_RX_DROP;
+	}
+
 	if (data[3] == NLPID_IP) {
 		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
 		dev = pvc->main;
@@ -896,13 +901,13 @@ static void fr_rx(struct sk_buff *skb)
 			printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
 			       "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
 			dev_kfree_skb_any(skb);
-			return;
+			return NET_RX_DROP;
 		}
 	} else {
 		printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
 		       "length = %i\n", hdlc_to_name(hdlc), data[3], skb->len);
 		dev_kfree_skb_any(skb);
-		return;
+		return NET_RX_DROP;
 	}
 
 	if (dev) {
@@ -913,14 +918,16 @@ static void fr_rx(struct sk_buff *skb)
 			stats->rx_compressed++;
 		skb->dev = dev;
 		netif_rx(skb);
-	} else
+		return NET_RX_SUCCESS;
+	} else {
 		dev_kfree_skb_any(skb);
-
-	return;
+		return NET_RX_DROP;
+	}
 
  rx_error:
 	hdlc->stats.rx_errors++; /* Mark error */
 	dev_kfree_skb_any(skb);
+	return NET_RX_DROP;
 }
 
 
diff -puN drivers/net/wan/hdlc_generic.c~generic-hdlc-updates drivers/net/wan/hdlc_generic.c
--- 25/drivers/net/wan/hdlc_generic.c~generic-hdlc-updates	Tue Jul 29 14:31:55 2003
+++ 25-akpm/drivers/net/wan/hdlc_generic.c	Tue Jul 29 14:31:55 2003
@@ -33,7 +33,7 @@
 #include <linux/hdlc.h>
 
 
-static const char* version = "HDLC support module revision 1.15";
+static const char* version = "HDLC support module revision 1.16";
 
 #undef DEBUG_LINK
 
@@ -60,12 +60,11 @@ static int hdlc_rcv(struct sk_buff *skb,
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	if (hdlc->proto.netif_rx)
-		hdlc->proto.netif_rx(skb);
-	else {
-		hdlc->stats.rx_dropped++; /* Shouldn't happen */
-		dev_kfree_skb(skb);
-	}
-	return 0;
+		return hdlc->proto.netif_rx(skb);
+
+	hdlc->stats.rx_dropped++; /* Shouldn't happen */
+	dev_kfree_skb(skb);
+	return NET_RX_DROP;
 }
 
 
@@ -280,10 +279,11 @@ EXPORT_SYMBOL(hdlc_ioctl);
 EXPORT_SYMBOL(register_hdlc_device);
 EXPORT_SYMBOL(unregister_hdlc_device);
 
-struct packet_type hdlc_packet_type=
+static struct packet_type hdlc_packet_type =
 {
 	.type = __constant_htons(ETH_P_HDLC),
 	.func = hdlc_rcv,
+	.data = (void *)1,
 };
 
 
diff -puN drivers/net/wan/hdlc_x25.c~generic-hdlc-updates drivers/net/wan/hdlc_x25.c
--- 25/drivers/net/wan/hdlc_x25.c~generic-hdlc-updates	Tue Jul 29 14:31:55 2003
+++ 25-akpm/drivers/net/wan/hdlc_x25.c	Tue Jul 29 14:31:55 2003
@@ -164,14 +164,21 @@ static void x25_close(hdlc_device *hdlc)
 
 
 
-static void x25_rx(struct sk_buff *skb)
+static int x25_rx(struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 
+	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+		hdlc->stats.rx_dropped++;
+		return NET_RX_DROP;
+	}
+
 	if (lapb_data_received(hdlc, skb) == LAPB_OK)
-		return;
+		return NET_RX_SUCCESS;
+
 	hdlc->stats.rx_errors++;
 	dev_kfree_skb_any(skb);
+	return NET_RX_DROP;
 }
 
 
diff -puN include/linux/hdlc.h~generic-hdlc-updates include/linux/hdlc.h
--- 25/include/linux/hdlc.h~generic-hdlc-updates	Tue Jul 29 14:31:55 2003
+++ 25-akpm/include/linux/hdlc.h	Tue Jul 29 14:31:55 2003
@@ -118,7 +118,7 @@ typedef struct hdlc_device_struct {
 		void (*stop)(struct hdlc_device_struct *hdlc);
 
 		void (*detach)(struct hdlc_device_struct *hdlc);
-		void (*netif_rx)(struct sk_buff *skb);
+		int (*netif_rx)(struct sk_buff *skb);
 		unsigned short (*type_trans)(struct sk_buff *skb,
 					     struct net_device *dev);
 		int id;		/* IF_PROTO_HDLC/CISCO/FR/etc. */

_