sdhci-pltfm: implement platform data passing
[safe/jmp/linux-2.6] / net / ax25 / ax25_out.c
index 3475a3a..37507d8 100644 (file)
@@ -8,18 +8,18 @@
  * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  */
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/spinlock.h>
 #include <linux/net.h>
+#include <linux/slab.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -70,11 +70,11 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
        ax25->dest_addr   = *dest;
 
        if (digi != NULL) {
-               if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+               ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC);
+               if (ax25->digipeat == NULL) {
                        ax25_cb_put(ax25);
                        return NULL;
                }
-               memcpy(ax25->digipeat, digi, sizeof(ax25_digi));
        }
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
@@ -93,6 +93,12 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
 #endif
        }
 
+       /*
+        * There is one ref for the state machine; a caller needs
+        * one more to put it back, just like with the existing one.
+        */
+       ax25_cb_hold(ax25);
+
        ax25_cb_add(ax25);
 
        ax25->state = AX25_STATE_1;
@@ -104,6 +110,8 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
        return ax25;                    /* We had to create it */
 }
 
+EXPORT_SYMBOL(ax25_send_frame);
+
 /*
  *     All outgoing AX.25 I frames pass via this routine. Therefore this is
  *     where the fragmentation of frames takes place. If fragment is set to
@@ -116,6 +124,12 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
        unsigned char *p;
        int frontlen, len, fragno, ka9qfrag, first = 1;
 
+       if (paclen < 16) {
+               WARN_ON_ONCE(1);
+               kfree_skb(skb);
+               return;
+       }
+
        if ((skb->len - 1) > paclen) {
                if (*skb->data == AX25_P_TEXT) {
                        skb_pull(skb, 1); /* skip PID */
@@ -147,8 +161,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
 
                        if (ka9qfrag == 1) {
                                skb_reserve(skbn, frontlen + 2);
-                               skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
-                               memcpy(skb_put(skbn, len), skb->data, len);
+                               skb_set_network_header(skbn,
+                                                     skb_network_offset(skb));
+                               skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
                                p = skb_push(skbn, 2);
 
                                *p++ = AX25_P_SEGMENT;
@@ -160,8 +175,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
                                }
                        } else {
                                skb_reserve(skbn, frontlen + 1);
-                               skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
-                               memcpy(skb_put(skbn, len), skb->data, len);
+                               skb_set_network_header(skbn,
+                                                     skb_network_offset(skb));
+                               skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
                                p = skb_push(skbn, 1);
                                *p = AX25_P_TEXT;
                        }
@@ -204,7 +220,7 @@ static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
        if (skb == NULL)
                return;
 
-       skb->nh.raw = skb->data;
+       skb_reset_network_header(skb);
 
        if (ax25->modulus == AX25_MODULUS) {
                frame = skb_push(skb, 1);
@@ -248,8 +264,6 @@ void ax25_kick(ax25_cb *ax25)
        if (start == end)
                return;
 
-       ax25->vs = start;
-
        /*
         * Transmit data until either we're out of data to send or
         * the window is full. Send a poll on the final I frame if
@@ -258,8 +272,13 @@ void ax25_kick(ax25_cb *ax25)
 
        /*
         * Dequeue the frame and copy it.
+        * Check for race with ax25_clear_queues().
         */
        skb  = skb_dequeue(&ax25->write_queue);
+       if (!skb)
+               return;
+
+       ax25->vs = start;
 
        do {
                if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
@@ -340,21 +359,18 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
 
        ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-       skb->dev = ax25->ax25_dev->dev;
-
-       ax25_queue_xmit(skb);
+       ax25_queue_xmit(skb, ax25->ax25_dev->dev);
 }
 
 /*
  *     A small shim to dev_queue_xmit to add the KISS control byte, and do
  *     any packet forwarding in operation.
  */
-void ax25_queue_xmit(struct sk_buff *skb)
+void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        unsigned char *ptr;
 
-       skb->protocol = htons(ETH_P_AX25);
-       skb->dev      = ax25_fwd_dev(skb->dev);
+       skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev));
 
        ptr  = skb_push(skb, 1);
        *ptr = 0x00;                    /* KISS */