}
 }
 
-static inline int
-qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
-                struct qeth_hdr **hdr, int ipv)
+static inline struct qeth_hdr *
+__qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
 {
-       int rc = 0;
 #ifdef CONFIG_QETH_VLAN
        u16 *tag;
-#endif
-
-       QETH_DBF_TEXT(trace, 6, "prepskb");
-       if (card->info.type == QETH_CARD_TYPE_OSN) {
-               *hdr = (struct qeth_hdr *)(*skb)->data;
-               return rc;
-       }
-        rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
-        if (rc)
-                return rc;
-#ifdef CONFIG_QETH_VLAN
-       if (card->vlangrp && vlan_tx_tag_present(*skb) &&
+       if (card->vlangrp && vlan_tx_tag_present(skb) &&
            ((ipv == 6) || card->options.layer2) ) {
                /*
                 * Move the mac addresses (6 bytes src, 6 bytes dest)
                 * to the beginning of the new header.  We are using three
                 * memcpys instead of one memmove to save cycles.
                 */
-               skb_push(*skb, VLAN_HLEN);
-               memcpy((*skb)->data, (*skb)->data + 4, 4);
-               memcpy((*skb)->data + 4, (*skb)->data + 8, 4);
-               memcpy((*skb)->data + 8, (*skb)->data + 12, 4);
-               tag = (u16 *)((*skb)->data + 12);
+               skb_push(skb, VLAN_HLEN);
+               memcpy(skb->data, skb->data + 4, 4);
+               memcpy(skb->data + 4, skb->data + 8, 4);
+               memcpy(skb->data + 8, skb->data + 12, 4);
+               tag = (u16 *)(skb->data + 12);
                /*
                 * first two bytes  = ETH_P_8021Q (0x8100)
                 * second two bytes = VLANID
                 */
                *tag = __constant_htons(ETH_P_8021Q);
-               *(tag + 1) = htons(vlan_tx_tag_get(*skb));
+               *(tag + 1) = htons(vlan_tx_tag_get(skb));
        }
 #endif
-       *hdr = (struct qeth_hdr *)
-               qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
-       if (*hdr == NULL)
-               return -EINVAL;
-       return 0;
+       return ((struct qeth_hdr *)
+               qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
+}
+
+static inline void
+__qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
+{
+       if (orig_skb != new_skb)
+               dev_kfree_skb_any(new_skb);
+}
+
+static inline struct sk_buff *
+qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
+                struct qeth_hdr **hdr, int ipv)
+{
+       struct sk_buff *new_skb;
+       
+       QETH_DBF_TEXT(trace, 6, "prepskb");
+
+        new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
+               if (new_skb == NULL)
+               return NULL;
+       *hdr = __qeth_prepare_skb(card, new_skb, ipv);
+       if (*hdr == NULL) {
+               __qeth_free_new_skb(skb, new_skb);
+               return NULL;
+       }
+       return new_skb;
 }
 
 static inline u8
         * check if buffer is empty to make sure that we do not 'overtake'
         * ourselves and try to fill a buffer that is already primed
         */
-       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
-               card->stats.tx_dropped++;
-               atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-               return -EBUSY;
-       }
+       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) 
+               goto out;
        if (ctx == NULL)
                queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
                                          QDIO_MAX_BUFFERS_PER_Q;
        else {
                buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx);
-               if (buffers_needed < 0) {
-                       card->stats.tx_dropped++;
-                       atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-                       return -EBUSY;
-               }
+               if (buffers_needed < 0) 
+                       goto out;
                queue->next_buf_to_fill =
                        (queue->next_buf_to_fill + buffers_needed) %
                        QDIO_MAX_BUFFERS_PER_Q;
                qeth_flush_buffers(queue, 0, index, flush_cnt);
        }
        return 0;
+out:
+       atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+       return -EBUSY;
 }
 
 static inline int
         * check if buffer is empty to make sure that we do not 'overtake'
         * ourselves and try to fill a buffer that is already primed
         */
-       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
-               card->stats.tx_dropped++;
+       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
                atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
                return -EBUSY;
        }
                                 * again */
                                if (atomic_read(&buffer->state) !=
                                                QETH_QDIO_BUF_EMPTY){
-                                       card->stats.tx_dropped++;
                                        qeth_flush_buffers(queue, 0, start_index, flush_count);
                                        atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
                                        return -EBUSY;
                         * free buffers) to handle eddp context */
                        if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
                                printk("eddp tx_dropped 1\n");
-                               card->stats.tx_dropped++;
                                rc = -EBUSY;
                                goto out;
                        }
                tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill);
                if (tmp < 0) {
                        printk("eddp tx_dropped 2\n");
-                       card->stats.tx_dropped++;
                        rc = - EBUSY;
                        goto out;
                }
 {
        int elements_needed = 0;
 
-        if (skb_shinfo(skb)->nr_frags > 0) {
+        if (skb_shinfo(skb)->nr_frags > 0) 
                 elements_needed = (skb_shinfo(skb)->nr_frags + 1);
-       }
-        if (elements_needed == 0 )
+        if (elements_needed == 0)
                 elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
                                         + skb->len) >> PAGE_SHIFT);
        if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){
-                PRINT_ERR("qeth_do_send_packet: invalid size of "
-                          "IP packet (Number=%d / Length=%d). Discarded.\n",
+                PRINT_ERR("Invalid size of IP packet "
+                         "(Number=%d / Length=%d). Discarded.\n",
                           (elements_needed+elems), skb->len);
                 return 0;
         }
         return elements_needed;
 }
 
+
 static inline int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
 {
        unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
        unsigned short tso_size = skb_shinfo(skb)->gso_size;
 #endif
+       struct sk_buff *new_skb, *new_skb2;
        int rc;
 
        QETH_DBF_TEXT(trace, 6, "sendpkt");
 
+       new_skb = skb;
+       if ((card->info.type == QETH_CARD_TYPE_OSN) &&
+           (skb->protocol == htons(ETH_P_IPV6)))
+               return -EPERM;
+       cast_type = qeth_get_cast_type(card, skb);
+       if ((cast_type == RTN_BROADCAST) &&
+           (card->info.broadcast_capable == 0))
+               return -EPERM;
+       queue = card->qdio.out_qs
+               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
        if (!card->options.layer2) {
                ipv = qeth_get_ip_version(skb);
                if ((card->dev->hard_header == qeth_fake_header) && ipv) {
-                               if ((skb = qeth_pskb_unshare(skb,GFP_ATOMIC)) == NULL) {
-                               card->stats.tx_dropped++;
-                               dev_kfree_skb_irq(skb);
-                               return 0;
-                       }
+                       new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
+                       if (!new_skb)
+                               return -ENOMEM;
                        if(card->dev->type == ARPHRD_IEEE802_TR){
-                               skb_pull(skb, QETH_FAKE_LL_LEN_TR);
+                               skb_pull(new_skb, QETH_FAKE_LL_LEN_TR);
                        } else {
-                               skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
+                               skb_pull(new_skb, QETH_FAKE_LL_LEN_ETH);
                        }
                }
        }
-       if ((card->info.type == QETH_CARD_TYPE_OSN) &&
-               (skb->protocol == htons(ETH_P_IPV6))) {
-               dev_kfree_skb_any(skb);
-               return 0;
-       }
-       cast_type = qeth_get_cast_type(card, skb);
-       if ((cast_type == RTN_BROADCAST) &&
-           (card->info.broadcast_capable == 0)){
-               card->stats.tx_dropped++;
-               card->stats.tx_errors++;
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
-       }
-       queue = card->qdio.out_qs
-               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
-
        if (skb_is_gso(skb))
                large_send = card->options.large_send;
-
-       /*are we able to do TSO ? If so ,prepare and send it from here */
+       /* check on OSN device*/
+       if (card->info.type == QETH_CARD_TYPE_OSN)
+               hdr = (struct qeth_hdr *)new_skb->data;
+       /*are we able to do TSO ? */
        if ((large_send == QETH_LARGE_SEND_TSO) &&
            (cast_type == RTN_UNSPEC)) {
-               rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
+               rc = qeth_tso_prepare_packet(card, new_skb, ipv, cast_type);
                if (rc) {
-                       card->stats.tx_dropped++;
-                       card->stats.tx_errors++;
-                       dev_kfree_skb_any(skb);
-                       return NETDEV_TX_OK;
+                       __qeth_free_new_skb(skb, new_skb);
+                       return rc;
                }
                elements_needed++;
-       } else {
-               if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
-                       QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
-                       return rc;
+       } else if (card->info.type != QETH_CARD_TYPE_OSN) {
+               new_skb2 = qeth_prepare_skb(card, new_skb, &hdr, ipv);
+               if (!new_skb2) {
+                       __qeth_free_new_skb(skb, new_skb);
+                       return -EINVAL;
                }
-               if (card->info.type != QETH_CARD_TYPE_OSN)
-                       qeth_fill_header(card, hdr, skb, ipv, cast_type);
+               if (new_skb != skb)
+                       __qeth_free_new_skb(new_skb2, new_skb);
+               new_skb = new_skb2;
+               qeth_fill_header(card, hdr, new_skb, ipv, cast_type);
        }
-
        if (large_send == QETH_LARGE_SEND_EDDP) {
-               ctx = qeth_eddp_create_context(card, skb, hdr);
+               ctx = qeth_eddp_create_context(card, new_skb, hdr);
                if (ctx == NULL) {
+                       __qeth_free_new_skb(skb, new_skb);
                        PRINT_WARN("could not create eddp context\n");
                        return -EINVAL;
                }
        } else {
-               int elems = qeth_get_elements_no(card,(void*) hdr, skb,
+               int elems = qeth_get_elements_no(card,(void*) hdr, new_skb,
                                                 elements_needed);
-               if (!elems)
+               if (!elems) {
+                       __qeth_free_new_skb(skb, new_skb);
                        return -EINVAL;
+               }
                elements_needed += elems;
        }
 
        if (card->info.type != QETH_CARD_TYPE_IQD)
-               rc = qeth_do_send_packet(card, queue, skb, hdr,
+               rc = qeth_do_send_packet(card, queue, new_skb, hdr,
                                         elements_needed, ctx);
        else
-               rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
+               rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
                                              elements_needed, ctx);
-       if (!rc){
+       if (!rc) {
                card->stats.tx_packets++;
                card->stats.tx_bytes += tx_bytes;
+               if (new_skb != skb)
+                       dev_kfree_skb_any(skb);
 #ifdef CONFIG_QETH_PERF_STATS
                if (tso_size &&
                   !(large_send == QETH_LARGE_SEND_NO)) {
                        card->perf_stats.large_send_bytes += tx_bytes;
                        card->perf_stats.large_send_cnt++;
                }
-               if (nr_frags > 0){
+               if (nr_frags > 0) {
                        card->perf_stats.sg_skbs_sent++;
                        /* nr_frags + skb->data */
                        card->perf_stats.sg_frags_sent +=
                                nr_frags + 1;
                }
 #endif /* CONFIG_QETH_PERF_STATS */
+       } else {
+               card->stats.tx_dropped++;
+               __qeth_free_new_skb(skb, new_skb);
        }
        if (ctx != NULL) {
                /* drop creator's reference */
                qeth_eddp_put_context(ctx);
                /* free skb; it's not referenced by a buffer */
-               if (rc == 0)
-                       dev_kfree_skb_any(skb);
-
+               if (!rc)
+                      dev_kfree_skb_any(new_skb);
        }
        return rc;
 }