lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Tue, 13 May 2008 21:03:29 +0200
From:	"Billy Smith" <gambuzo@...il.com>
To:	netdev@...r.kernel.org
Subject: 3Com 3c905 - Problems trying to send a frame in my own kernel module

Hi all,
I've been trying to write a simple network driver for the 3Com 3c509B
device in Linux, just for fun. Unfortunately, with no success. In my
"module" I try to only send one frame, but it never gets downloaded by
the NIC.
My kernel is 2.6.18, the bus is PCI.
I get all registers set as expected. I suppose something is wrong with
DMA bus mastering. It seems as if the NIC doesn't download the data
from the addresses I provide.
I get the dnInProg bit set in the DmaCtrl register (one of the NIC
registers), so "Download is in progress", but in fact it doesn't work.

Below I put my code (somewhat modified to be short) in two versions,
one with dma_pool_create/alloc() calls, and the other with
dma_map_single(). Both produce the same results, but with no success
(sending one frame).

I based the code on the "3C90x and 3C90xB NICs Technical Reference"
from 3Com, published August 1998.

Could anybody help me ? I'm quite discouraged and frustrated. What is
wrong with the code? Did I miss something to get DMA working?

###########################################################
// dma_map_single() version

#define FRAME_SIZE 64
// Example ARP Request with random padding
u8 string[FRAME_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,...};
unsigned long HostRegBaseAddr; // NIC registers
u32 *DPD_mem=NULL;
u8 *frame_mem=NULL;
dma_addr_t DPD = 0, frame = 0;
struct pci_dev *pdev = NULL;
...
pci_enable_device(pdev);
pci_set_master(pdev);
if (request_irq(pdev->irq, drvhandler, IRQF_SHARED, "3ComNIC", (void*)
&netdev) == 0)
{error... return -1;}

// Reset the device
iowrite16(GlobalReset,HostRegBaseAddr+14);
while (ioread16(HostRegBaseAddr+14)& cmdInProgress)
printk("Waiting...\n");


// Enable indications and interrupts
iowrite16(SetIndicationEnable | txComplete|dnComplete,HostRegBaseAddr+14);
iowrite16(SetInterruptEnable | txComplete|dnComplete,HostRegBaseAddr+14);
if ((frame_mem=kmalloc(FRAME_SIZE, GFP_DMA)) != NULL)
{
  for (i=0; i<FRAME_SIZE; i++)
  frame_mem[i] = string[i];
}
else {error...}
if ((DPD_mem = kmalloc(16, GFP_DMA)) != NULL)
{
  // Construct the Data Packet Descriptor

  DPD_mem[0] = 0; // DnNextPtr - there is no next DPD
  DPD_mem[1] = 0x80008000; // FSH
  DPD_mem[2] = frame; // FirstDnFragAddr
  DPD_mem[3] = 0x8000000040; // FirstDnFragLen; 3c means the frame length


}
else {error...}
DPD = dma_map_single(&pdev->dev, DPD_mem, 16, DMA_TO_DEVICE);
if (!DPD) {error...}
frame = dma_map_single(&pdev->dev, frame_mem, FRAME_SIZE, DMA_TO_DEVICE);
if (!frame) {error...}
// Send the frame
iowrite16(TxEnable, HostRegBaseAddr+14);
iowrite32(DPD, HostRegBaseAddr+0x24);
...
#############################################################

###########################################################
// dma_pool_create/alloc() version



#define FRAME_SIZE 64
// Example ARP Request with random padding
u8 string[FRAME_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,...};
unsigned long HostRegBaseAddr; // NIC registers
struct dma_pool *DPD_pool=NULL, *frame_pool=NULL;
unsigned long DPD_handle=0, frame_handle=0;
dma_addr_t DPD = 0, frame = 0;
struct pci_dev *pdev = NULL;
...
pci_enable_device(pdev);
pci_set_master(pdev);
if (request_irq(pdev->irq, drvhandler, IRQF_SHARED, "3ComNIC", (void*)
&netdev) == 0)
{error... return -1;}

// Reset the device
iowrite16(GlobalReset,HostRegBaseAddr+14);
while (ioread16(HostRegBaseAddr+14)& cmdInProgress)
printk("Waiting...\n");
// Enable indications and interrupts
iowrite16(SetIndicationEnable | txComplete|dnComplete,HostRegBaseAddr+14);
iowrite16(SetInterruptEnable | txComplete|dnComplete,HostRegBaseAddr+14);
// Allocate DMA-memory for storing the DPD
if ((DPD_pool = dma_pool_create("DPD_pool", &(pdev->dev), 16, 16,
4096)) == NULL)
{
  printk(KERN_ALERT "DPD_pool error");
  return -1;
}
if ((frame_pool = dma_pool_create("frame_pool", &(pdev->dev),
FRAME_SIZE, 16, 4096)) == NULL)
{
  printk(KERN_ALERT "frame_pool error");
  return -1;
}
printk("Pools OK\n");
if ((DPD = dma_pool_alloc(DPD_pool, GFP_DMA, &DPD_handle)) == NULL)
{
  printk(KERN_ALERT "DPD alloc error\n");
  return -1;
}
if ((frame = dma_pool_alloc(frame_pool, GFP_DMA,
&frame_handle))==NULL)
{
  printk(KERN_ALERT "frame alloc error\n");
  return -1;
}
  for (i=0; i<FRAME_SIZE; i++)
  frame[i] = string[i];
// Construct the Data Packet Descriptor

DPD[0] = 0; // DnNextPtr
DPD[1] = 0x80008000; // FSH
DPD[2] = frame_handle; // FirstDnFragAddr
DPD[3] = 0x80000040; // FirstDnFragLen

// Send the frame
iowrite16(TxEnable, HostRegBaseAddr+14);
iowrite32(DPD_handle, HostRegBaseAddr+0x24);
...
#############################################################



I attach the full module code. Thank you,
gambuzo.

Download attachment "drv_tx.c" of type "application/octet-stream" (7284 bytes)

Download attachment "drv_tx1.c" of type "application/octet-stream" (7622 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ