domingo, 8 de diciembre de 2013

Writing bytes from a NE2000 ethernet card part 1

Hi.

Well, today we will write some bytes in a ethernet network. We will use a NE2000 lan card. I hope you still have one.

Documentation needed for this is:

Writing Drivers for the
DP8390 NIC Family of
Ethernet Controllers

From National Semiconductor.


My PCI card is in 0xbf00 as base address. You might need to know the base address of your card. Some are 0x300.


Compile with gcc -O -o testne2000 testne2000.c kbhit.c

testne2000.c:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
#if defined(__linux__)  &&  __GNU_LIBRARY__ == 1
#include <asm/io.h>
#else
#include <sys/io.h>
#endif
#if !defined(__OPTIMIZE__)
#error You must compile this driver with "-O"!
#endif

#define COMMAND 0xbf00
#define DATACONFIGURATION COMMAND+0x0E

#define COMMAND  0xbf00
#define PAGESTART  COMMAND+01
#define PAGESTOP  COMMAND+02
#define BOUNDARY  COMMAND+03
#define TRANSMITSTATUS  COMMAND+04
#define TRANSMITPAGE  COMMAND+04
#define TRANSMITBYTECOUNT0  COMMAND+0x05
#define NCR  COMMAND+05
#define TRANSMITBYTECOUNT1  COMMAND+0x06
#define INTERRUPTSTATUS  COMMAND+0x07
#define CURRENT  COMMAND+07
#define REMOTESTARTADDRESS0 COMMAND+0x08
#define CRDMA0  COMMAND+0x08
#define REMOTESTARTADDRESS1 COMMAND+0x09
#define CRDMA1  COMMAND+0x09
#define REMOTEBYTECOUNT0  COMMAND+0x0A
#define REMOTEBYTECOUNT1  COMMAND+0x0B
#define RECEIVESTATUS  COMMAND+0x0C
#define RECEIVECONFIGURATION  COMMAND+0x0C
#define TRANSMITCONFIGURATION  COMMAND+0x0D
#define FAE TALLY  COMMAND+0x0D
#define DATACONFIGURATION  COMMAND+0x0E
#define CRC TALLY  COMMAND+0x0E
#define INTERRUPTMASK  COMMAND+0x0F
#define MISS PKT TALLY  COMMAND+0x0F
#define IOPORT COMMAND+0x10

#define PSTART  0x46
#define PSTOP 0x80
#define TRANSMITBUFFER 0x40


#define NE_P1_PAR0      0x01           // Physical Address Register 0
#define NE_P1_PAR1      0x02           // Physical Address Register 1
#define NE_P1_PAR2      0x03           // Physical Address Register 2
#define NE_P1_PAR3      0x04           // Physical Address Register 3
#define NE_P1_PAR4      0x05           // Physical Address Register 4
#define NE_P1_PAR5      0x06           // Physical Address Register 5
#define NE_P1_CURR      0x07           // Current RX ring-buffer page
#define NE_P1_MAR0      0x08           // Multicast Address Register 0
#define NE_P1_MAR1      0x09           // Multicast Address Register 1
#define NE_P1_MAR2      0x0A           // Multicast Address Register 2
#define NE_P1_MAR3      0x0B           // Multicast Address Register 3
#define NE_P1_MAR4      0x0C           // Multicast Address Register 4
#define NE_P1_MAR5      0x0D           // Multicast Address Register 5
#define NE_P1_MAR6      0x0E           // Multicast Address Register 6
#define NE_P1_MAR7      0x0F           // Multicast Address Register 7
#define ETHER_ADDR_LEN 6
struct ether_addr {
unsigned short addr[ETHER_ADDR_LEN];
};

struct ne {
  //dev_t devno;                          // Device number
  struct ether_addr hwaddr;               // MAC address

  unsigned short iobase;                // Configured I/O base
  unsigned short irq;                   // Configured IRQ
  unsigned short membase;               // Configured memory base
  unsigned short memsize;               // Configured memory size

  unsigned short asic_addr;             // ASIC I/O bus address
  unsigned short nic_addr;              // NIC (DP8390) I/O bus address
  
  //struct interrupt intr;                // Interrupt object for driver
  //struct dpc dpc;                       // DPC for driver

  unsigned short rx_ring_start;         // Start address of receive ring
  unsigned short rx_ring_end;           // End address of receive ring

  unsigned char rx_page_start;          // Start of receive ring
  unsigned char rx_page_stop;           // End of receive ring
  unsigned char next_pkt;               // Next unread received packet

  //struct event rdc;                     // Remote DMA completed event
  //struct event ptx;                     // Packet transmitted event
  //struct mutex txlock;                  // Transmit lock
};

 static int ne_probe(struct ne *ne) {
  unsigned char byte,i;

  // Reset
  //msleep(5000);
  
  byte=inb(0xbf00);
outb(0x21,0xbf00);
 // sleep(1);
printf("Command reg %x\n",byte);
outb(0x58,DATACONFIGURATION);
   outb(0x00,REMOTEBYTECOUNT0);
outb(0x00,REMOTEBYTECOUNT1);
   outb(0x00,RECEIVECONFIGURATION);
outb(0x20,TRANSMITPAGE); 
   outb(0x02,TRANSMITCONFIGURATION);
outb(0x26,PAGESTART);
outb(0x26,BOUNDARY);
   outb(0x40,PAGESTOP); 
outb(0x61,COMMAND);

for (i = 0; i < 6; i++) 
{
    outb(ne->hwaddr.addr[i],COMMAND + NE_P1_PAR0 + i);
}
for (i = 0; i < ETHER_ADDR_LEN; i++)
{
printf("PAR %x %x\n",inb(COMMAND + NE_P1_PAR0 + i),ne->hwaddr.addr[i]);
}
   // Actually the ethernet address is overwritten later on wit 0xA5A5. You can fix it. I will put a useful payload later
outb(0x26,CURRENT);
outb(0x22,COMMAND);
outb(0xff,INTERRUPTSTATUS); 
outb(0x0B,INTERRUPTMASK);
   outb(0x00,TRANSMITCONFIGURATION);

//send a packet
 int count =100;
 outb(count & 0xff,REMOTEBYTECOUNT0);
 outb(count >>8 , REMOTEBYTECOUNT1);
 outb(0x00, REMOTESTARTADDRESS0);
 outb(TRANSMITBUFFER, REMOTESTARTADDRESS1);
 outb(0x12,COMMAND);
for (i=0;i<100;i++)
 outw(0xA5A5,IOPORT);
int s=0;
s=inb(INTERRUPTSTATUS);
while(s!=0x40)
s=inb(INTERRUPTSTATUS);
printf("Interrup status %x\n",s);
outb(0x40,INTERRUPTSTATUS);
s=inb(INTERRUPTSTATUS);
printf("Interrup status %x\n",s);
outb(TRANSMITBUFFER,TRANSMITPAGE);
outb(count & 0xff,TRANSMITBYTECOUNT0);
outb(count >>8 ,TRANSMITBYTECOUNT1);
outb(0x26,COMMAND);
return 1;
}

int main(char argc, char **argv)
{
if (iopl(3)) {perror("iopl error"); exit(1);}
struct ne *NIC;
NIC = (struct ne *) malloc(sizeof(struct ne));
NIC->hwaddr.addr[0]=0x00;
NIC->hwaddr.addr[1]=0xA0;
NIC->hwaddr.addr[2]=0xFF;
NIC->hwaddr.addr[3]=0xFF;
NIC->hwaddr.addr[4]=0x58;
NIC->hwaddr.addr[5]=0x33;
int i;

  ne_probe(NIC);
  return 0;
}

The getch and hitkb are not mine: (those are turboc things I guess)

kbhit.c

#include "kbhit.h"
#include <termios.h>
#include <unistd.h>   // for read()

static struct termios initial_settings, new_settings;
static int peek_character = -1;

void init_keyboard()
{
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_lflag &= ~ISIG;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
}

void close_keyboard()
{
    tcsetattr(0, TCSANOW, &initial_settings);
}

int kbhit()
{
unsigned char ch;
int nread;

    if (peek_character != -1) return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);
    if(nread == 1) 
    {
        peek_character = ch;
        return 1;
    }
    return 0;
}

int readch()
{
char ch;

    if(peek_character != -1) 
    {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}

int getch()
{
char ch;

    if(peek_character != -1) 
    {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}


The kbhit.n

#ifndef KBHIT_H
#define KBHIT_H

void   init_keyboard(void);
void   close_keyboard(void);
int      kbhit(void);
int     readch(void); 
int     getch(void); 

#endif 


The frame cannot be captured with wireshark because it is being written directly to the hardware!. 
I will also clean up the code later.

Check the screenshoot.



No hay comentarios:

Publicar un comentario