Autopadding was sometimes overwriting the struct list_head at the end
[people/xl0/gpxe.git] / src / drivers / net / rtl8139.c
index 5e37f9c..4981329 100644 (file)
@@ -367,8 +367,10 @@ static void rtl_close ( struct net_device *netdev ) {
  */
 static int rtl_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
        struct rtl8139_nic *rtl = netdev->priv;
-       int align;
-       int pad_len;
+       void *data;
+       size_t len;
+       size_t headroom;
+       signed int pad_len;
 
        /* Check for space in TX ring */
        if ( rtl->tx.pkb[rtl->tx.next] != NULL ) {
@@ -376,11 +378,18 @@ static int rtl_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
                return -ENOBUFS;
        }
 
-       /* Align packet data */
-       align = ( virt_to_bus ( pkb->data ) & 0x3 );
-       pkb_push ( pkb, align );
-       memmove ( pkb->data, pkb->data + align, pkb_len ( pkb ) - align );
-       pkb_unput ( pkb, align );
+       /* Move packet data to start of packet buffer.  This will both
+        * align the data (since packet buffers are aligned to
+        * PKB_ALIGN) and give us sufficient space for the
+        * zero-padding
+        */
+       data = pkb->data;
+       len = pkb_len ( pkb );
+       headroom = pkb_headroom ( pkb );
+       pkb_push ( pkb, headroom );
+       memmove ( pkb->data, data, len );
+       pkb_unput ( pkb, headroom );
+       assert ( ( virt_to_bus ( pkb->data ) & 0x3 ) == 0 );
 
        /* Pad to minimum packet length */
        pad_len = ( ETH_ZLEN - pkb_len ( pkb ) );