Hi!

There is a bug in the SMC9194 (drivers/net/smc9194.c) in function 
smc_wait_to_send_packet() that will cause packet destroying
on some special packet sizes. 

I have included a little tool (ndtest.c)
whitch can send UDP-Packets with a user defined sizes. With
a ethernet analyzer (e.g. tcpdump) on a second host you can check
outgoing packets for correctness.

USAGE: ndtest <IP> <port> <size> 


Resulting protocol:

UDP data size         |  resulting ethernet frame size     
(ndtest arg)       |  (with network analyzer)
------------------------------------------------
466           |  512 (ok)
467           |  512 (packet sliced !)
468           |  514 (UDP-crc wrong !)
469           |  514 (packet sliced !)
470           |  516 (Pkt ok)

722           |  768 (ok)
723           |  768 (packet sliced !)
724           |  770 (UDP-crc wrong !)
725           |  770 (packet sliced !)
726           |  772 (ok)

978           |  1024 (ok)
979           |  1024 (packet sliced !)
980           |  1026 (UDP-crc wrong !)
981           |  1026 (packet sliced !)
982           |  1028 (ok)

... (s.o.)


As you can see every ethernet paket with a size 
of (256 + [1..3]) * X will be destroyed!


The problem is that the smc9194-driver didn't recognize
the correct memory usage of the sending packet. The
driver calculates the number of pages with

  numPages = length / 256;

but sending packets has always a 6-byte-header on 
a smc919x chip! Bytes will be lost at the end of the packet!
So the correct calculation is

  numPages = ((length & 0xfffe) + 6) / 256;

(The last bytes of an odd packet is included in the
6-byte-header. That's because of the anded 0xfffe)

I have included a patch (smc9194.patch) that will change this in the driver.


The patch was made for Kernel 2.2.10. Because the driver is from
1996 and no changes were made since 1996 this bug is in every
Linux Kernel I found. 
I have test this patch on several machines with smc9194 and 
smc9196 chip and now it works correctly.



Best regards,

SMA Regelsysteme GmbH
i.A. Heiko Pruessing
- Software Development -
Hannoversche Strasse 1-5
34266 Niestetal (Germany)
Tel: +49 (0)561-9522-274
Fax: +49 (0)561-9522-295
E-Mail: [EMAIL PROTECTED]
        [EMAIL PROTECTED]
Web:    www.sma.de
        homepages.fh-giessen.de/~hg6256    
--- drivers/net/smc9194_old.c   Thu Mar 11 01:51:35 1999
+++ drivers/net/smc9194.c       Sun Apr 30 20:36:08 2000
@@ -45,10 +45,12 @@
  .                              Fixed bug reported by Gardner Buchanan in
  .                                smc_enable, with outw instead of outb
  .     03/06/96  Erik Stahlman  Added hardware multicast from Peter Cammaert
+ .     04/14/00  Heiko Pruessing (SMA Regelsysteme)  Fixed bug in chip memory
+ .                              allocation
  ----------------------------------------------------------------------------*/
 
 static const char *version =
-       "smc9194.c:v0.12 03/06/96 by Erik Stahlman ([EMAIL PROTECTED])\n";
+       "smc9194.c:v0.13 04/14/00 by Erik Stahlman ([EMAIL PROTECTED])\n";
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -562,11 +564,15 @@
 
        length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 
+               
        /*
-       . the MMU wants the number of pages to be the number of 256 bytes
-       . 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+       ** The MMU wants the number of pages to be the number of 256 bytes
+       ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+       **
+       ** Pkt size for allocating is data length +6 (for additional status words,
+       ** length and ctl!) If odd size last byte is included in this header.
        */
-       numPages = length / 256;
+       numPages =  ((length & 0xfffe) + 6) / 256;
 
        if (numPages > 7 ) {
                printk(CARDNAME": Far too big packet error. \n");
/*
** ndtest.c  (network driver test)
** This simple program was created to test the smc9194 linux driver.
** It sends a (UDP) packet of a user defined size on the wire.
**
** Copyright (C) 2000 by Heiko Pruessing (SMA Regelsysteme GmbH)
** This software may be used and distributed according to the terms
** of the GNU Public License, incorporated herein by references.
**
** Arguments:
**    host  = destination host (IP only)
**    port  = destination port
**    size  = size of the (UDP) packet
**
** author:
**    Heiko Pruessing
**
** History:
**    20/04/00  Heiko Pruessing   created for testing
*/

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char ** argv)
{
   int i;
   unsigned char Buffer[50000];
   int iBufferSize;
   char * cHost;
   int iPort;

   int sockfd;
   struct sockaddr_in serv_addr;

   if (argc < 4)
   {
      printf("USAGE: %s <host> <port> <size of packet>\n", argv[0]);
      exit();
   }
   else
   {
      cHost = argv[1];
      iPort = atoi(argv[2]);
      iBufferSize = atoi(argv[3]);
   }

   for(i=0;i<iBufferSize;i++)
   {
      Buffer[i] = (unsigned char)i;
   }


   printf("Send UDP packet to %s:%d of len %d\n", cHost, iPort, iBufferSize);
   

   bzero((char*)&serv_addr, sizeof(serv_addr));
   serv_addr.sin_family      = AF_INET;
   serv_addr.sin_addr.s_addr = inet_addr( cHost );
   serv_addr.sin_port        = htons( iPort );
  
   if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
   {
      printf("can not open socket....\n");
      exit();
   }

   if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))< 0)
   {
      printf("can not connect...\n");
      exit();
   }

   send(sockfd, Buffer, iBufferSize, 0);

   close( sockfd );
}

   

Reply via email to