2014-05-07 09:14:05 +04:00
# include <module.h>
# include <logging.h>
# include <printf.h>
# include <pci.h>
# include <mem.h>
2014-05-08 10:08:34 +04:00
# include <list.h>
2014-05-07 09:14:05 +04:00
# include <ipv4.h>
# include <mod/shell.h>
2014-05-09 06:29:23 +04:00
# define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24))
# define htons(s) ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) )
2014-05-14 10:56:54 +04:00
# define ntohl(l) htonl((l))
# define ntohs(s) htons((s))
2014-05-09 06:29:23 +04:00
2014-05-07 09:14:05 +04:00
static uint32_t rtl_device_pci = 0x00000000 ;
static void find_rtl ( uint32_t device , uint16_t vendorid , uint16_t deviceid , void * extra ) {
if ( ( vendorid = = 0x10ec ) & & ( deviceid = = 0x8139 ) ) {
* ( ( uint32_t * ) extra ) = device ;
}
}
# define RTL_PORT_MAC 0x00
# define RTL_PORT_MAR 0x08
# define RTL_PORT_TXSTAT 0x10
# define RTL_PORT_TXBUF 0x20
# define RTL_PORT_RBSTART 0x30
# define RTL_PORT_CMD 0x37
# define RTL_PORT_RXPTR 0x38
# define RTL_PORT_RXADDR 0x3A
# define RTL_PORT_IMR 0x3C
# define RTL_PORT_ISR 0x3E
# define RTL_PORT_TCR 0x40
# define RTL_PORT_RCR 0x44
# define RTL_PORT_RXMISS 0x4C
# define RTL_PORT_CONFIG 0x52
static int rtl_irq = 0 ;
static uint32_t rtl_iobase = 0 ;
static uint8_t * rtl_rx_buffer ;
2014-05-07 11:17:31 +04:00
static uint8_t * rtl_tx_buffer [ 5 ] ;
2014-05-14 09:09:15 +04:00
static uint8_t mac [ 6 ] ;
2014-05-07 09:14:05 +04:00
2014-05-08 10:08:34 +04:00
static uint8_t * last_packet = NULL ;
2014-05-07 09:14:05 +04:00
static uintptr_t rtl_rx_phys ;
2014-05-07 11:17:31 +04:00
static uintptr_t rtl_tx_phys [ 5 ] ;
2014-05-07 09:14:05 +04:00
static uint32_t cur_rx = 0 ;
2014-05-07 10:29:17 +04:00
static int dirty_tx = 0 ;
2014-05-07 09:14:05 +04:00
2014-05-08 10:08:34 +04:00
static list_t * rx_wait ;
2014-05-14 09:09:15 +04:00
# define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
# define IPV4_PROT_UDP 17
# define DHCP_MAGIC 0x63825363
2014-05-14 09:59:36 +04:00
uint32_t ip_aton ( const char * in ) {
char ip [ 16 ] ;
char * c = ip ;
int out [ 4 ] ;
char * i ;
memcpy ( ip , in , strlen ( in ) < 15 ? strlen ( in ) + 1 : 15 ) ;
ip [ 15 ] = ' \0 ' ;
i = ( char * ) lfind ( c , ' . ' ) ;
* i = ' \0 ' ;
out [ 0 ] = atoi ( c ) ;
c + = strlen ( c ) + 1 ;
i = ( char * ) lfind ( c , ' . ' ) ;
* i = ' \0 ' ;
out [ 1 ] = atoi ( c ) ;
c + = strlen ( c ) + 1 ;
i = ( char * ) lfind ( c , ' . ' ) ;
* i = ' \0 ' ;
out [ 2 ] = atoi ( c ) ;
c + = strlen ( c ) + 1 ;
out [ 3 ] = atoi ( c ) ;
return ( ( out [ 0 ] < < 24 ) | ( out [ 1 ] < < 16 ) | ( out [ 2 ] < < 8 ) | ( out [ 3 ] ) ) ;
}
void ip_ntoa ( uint32_t src_addr , char * out ) {
sprintf ( out , " %d.%d.%d.%d " ,
( src_addr & 0xFF000000 ) > > 24 ,
( src_addr & 0xFF0000 ) > > 16 ,
( src_addr & 0xFF00 ) > > 8 ,
( src_addr & 0xFF ) ) ;
}
2014-05-14 09:09:15 +04:00
uint16_t calculate_ipv4_checksum ( struct ipv4_packet * p ) {
uint32_t sum = 0 ;
uint16_t * s = ( uint16_t * ) p ;
/* TODO: Checksums for options? */
for ( int i = 0 ; i < 10 ; + + i ) {
sum + = ntohs ( s [ i ] ) ;
}
if ( sum > 0xFFFF ) {
sum = ( sum > > 16 ) + ( sum & 0xFFFF ) ;
}
return ~ ( sum & 0xFFFF ) & 0xFFFF ;
}
static size_t write_dhcp_packet ( uint8_t * buffer ) {
size_t offset = 0 ;
size_t payload_size = sizeof ( struct dhcp_packet ) ;
/* First, let's figure out how big this is supposed to be... */
uint8_t dhcp_options [ ] = {
53 , /* Message type */
1 , /* Length: 1 */
1 , /* Discover */
255 , /* END */
} ;
payload_size + = sizeof ( dhcp_options ) ;
/* Then, let's write an ethernet frame */
struct ethernet_packet eth_out = {
. source = { mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] } ,
. destination = BROADCAST_MAC ,
. type = htons ( 0x0800 ) ,
} ;
memcpy ( & buffer [ offset ] , & eth_out , sizeof ( struct ethernet_packet ) ) ;
offset + = sizeof ( struct ethernet_packet ) ;
/* Prepare the IPv4 header */
uint16_t _length = htons ( sizeof ( struct ipv4_packet ) + sizeof ( struct udp_packet ) + payload_size ) ;
uint16_t _ident = htons ( 1 ) ;
struct ipv4_packet ipv4_out = {
. version_ihl = ( ( 0x4 < < 4 ) | ( 0x5 < < 0 ) ) , /* 4 = ipv4, 5 = no options */
. dscp_ecn = 0 , /* not setting either of those */
. length = _length ,
. ident = _ident ,
. flags_fragment = 0 ,
. ttl = 0x40 ,
. protocol = IPV4_PROT_UDP ,
. checksum = 0 , /* fill this in later */
2014-05-14 09:59:36 +04:00
. source = htonl ( ip_aton ( " 0.0.0.0 " ) ) ,
. destination = htonl ( ip_aton ( " 255.255.255.255 " ) ) , /* XXX need macros for this */
2014-05-14 09:09:15 +04:00
} ;
uint16_t checksum = calculate_ipv4_checksum ( & ipv4_out ) ;
ipv4_out . checksum = htons ( checksum ) ;
memcpy ( & buffer [ offset ] , & ipv4_out , sizeof ( struct ipv4_packet ) ) ;
offset + = sizeof ( struct ipv4_packet ) ;
uint16_t _udp_source = htons ( 68 ) ;
uint16_t _udp_destination = htons ( 67 ) ;
uint16_t _udp_length = htons ( sizeof ( struct udp_packet ) + payload_size ) ;
/* Now let's build a UDP packet */
struct udp_packet udp_out = {
. source_port = _udp_source ,
. destination_port = _udp_destination ,
. length = _udp_length ,
. checksum = 0 ,
} ;
/* XXX calculate checksum here */
memcpy ( & buffer [ offset ] , & udp_out , sizeof ( struct udp_packet ) ) ;
offset + = sizeof ( struct udp_packet ) ;
/* BOOTP headers */
struct dhcp_packet bootp_out = {
. op = 1 ,
. htype = 1 ,
. hlen = 6 , /* mac address... */
. hops = 0 ,
. xid = htonl ( 0x1337 ) , /* transaction id */
. secs = 0 ,
. flags = 0 ,
. ciaddr = 0x000000 ,
. yiaddr = 0x000000 ,
. siaddr = 0x000000 ,
. giaddr = 0x000000 ,
. chaddr = { mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] , 0x00 } ,
. sname = { 0 } ,
. file = { 0 } ,
. magic = htonl ( DHCP_MAGIC ) ,
} ;
memcpy ( & buffer [ offset ] , & bootp_out , sizeof ( struct dhcp_packet ) ) ;
offset + = sizeof ( struct dhcp_packet ) ;
memcpy ( & buffer [ offset ] , & dhcp_options , sizeof ( dhcp_options ) ) ;
offset + = sizeof ( dhcp_options ) ;
return offset ;
}
2014-05-14 12:44:31 +04:00
static size_t write_dns_packet ( uint8_t * buffer , size_t queries_len , uint8_t * queries ) {
2014-05-14 09:09:15 +04:00
size_t offset = 0 ;
2014-05-14 12:44:31 +04:00
size_t payload_size = sizeof ( struct dns_packet ) + queries_len ;
2014-05-14 09:09:15 +04:00
/* Then, let's write an ethernet frame */
struct ethernet_packet eth_out = {
. source = { mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] } ,
. destination = BROADCAST_MAC ,
. type = htons ( 0x0800 ) ,
} ;
memcpy ( & buffer [ offset ] , & eth_out , sizeof ( struct ethernet_packet ) ) ;
offset + = sizeof ( struct ethernet_packet ) ;
/* Prepare the IPv4 header */
uint16_t _length = htons ( sizeof ( struct ipv4_packet ) + sizeof ( struct udp_packet ) + payload_size ) ;
uint16_t _ident = htons ( 1 ) ;
struct ipv4_packet ipv4_out = {
. version_ihl = ( ( 0x4 < < 4 ) | ( 0x5 < < 0 ) ) , /* 4 = ipv4, 5 = no options */
. dscp_ecn = 0 , /* not setting either of those */
. length = _length ,
. ident = _ident ,
. flags_fragment = 0 ,
. ttl = 0x40 ,
. protocol = IPV4_PROT_UDP ,
. checksum = 0 , /* fill this in later */
2014-05-14 09:59:36 +04:00
. source = htonl ( ip_aton ( " 10.0.2.15 " ) ) ,
. destination = htonl ( ip_aton ( " 10.0.2.3 " ) ) ,
2014-05-14 09:09:15 +04:00
} ;
uint16_t checksum = calculate_ipv4_checksum ( & ipv4_out ) ;
ipv4_out . checksum = htons ( checksum ) ;
memcpy ( & buffer [ offset ] , & ipv4_out , sizeof ( struct ipv4_packet ) ) ;
offset + = sizeof ( struct ipv4_packet ) ;
uint16_t _udp_source = htons ( 50053 ) ; /* Use an ephemeral port */
uint16_t _udp_destination = htons ( 53 ) ;
uint16_t _udp_length = htons ( sizeof ( struct udp_packet ) + payload_size ) ;
/* Now let's build a UDP packet */
struct udp_packet udp_out = {
. source_port = _udp_source ,
. destination_port = _udp_destination ,
. length = _udp_length ,
. checksum = 0 ,
} ;
/* XXX calculate checksum here */
memcpy ( & buffer [ offset ] , & udp_out , sizeof ( struct udp_packet ) ) ;
offset + = sizeof ( struct udp_packet ) ;
/* DNS header */
struct dns_packet dns_out = {
. qid = htons ( 0 ) ,
. flags = htons ( 0x0100 ) , /* Standard query */
. questions = htons ( 1 ) , /* 1 question */
. answers = htons ( 0 ) ,
. authorities = htons ( 0 ) ,
. additional = htons ( 0 ) ,
} ;
memcpy ( & buffer [ offset ] , & dns_out , sizeof ( struct dns_packet ) ) ;
offset + = sizeof ( struct dns_packet ) ;
2014-05-14 12:44:31 +04:00
memcpy ( & buffer [ offset ] , queries , queries_len ) ;
offset + = queries_len ;
2014-05-14 09:09:15 +04:00
return offset ;
}
2014-05-08 10:08:34 +04:00
2014-05-14 12:23:12 +04:00
static size_t print_dns_name ( fs_node_t * tty , struct dns_packet * dns , size_t offset ) {
uint8_t * bytes = ( uint8_t * ) dns ;
while ( 1 ) {
uint8_t c = bytes [ offset ] ;
if ( c = = 0 ) {
offset + + ;
return offset ;
} else if ( c > = 0xC0 ) {
uint16_t ref = ( ( c - 0xC0 ) < < 8 ) + bytes [ offset + 1 ] ;
print_dns_name ( tty , dns , ref ) ;
offset + + ;
offset + + ;
return offset ;
} else {
for ( int i = 0 ; i < c ; + + i ) {
fprintf ( tty , " %c " , bytes [ offset + 1 + i ] ) ;
}
fprintf ( tty , " . " ) ;
offset + = c + 1 ;
}
}
}
2014-05-14 12:44:31 +04:00
static void parse_dns_response ( fs_node_t * tty , void * last_packet ) {
struct ethernet_packet * eth = ( struct ethernet_packet * ) last_packet ;
uint16_t eth_type = ntohs ( eth - > type ) ;
fprintf ( tty , " Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x) \n " ,
eth - > source [ 0 ] , eth - > source [ 1 ] , eth - > source [ 2 ] ,
eth - > source [ 3 ] , eth - > source [ 4 ] , eth - > source [ 5 ] ,
eth - > destination [ 0 ] , eth - > destination [ 1 ] , eth - > destination [ 2 ] ,
eth - > destination [ 3 ] , eth - > destination [ 4 ] , eth - > destination [ 5 ] ,
eth_type ) ;
struct ipv4_packet * ipv4 = ( struct ipv4_packet * ) eth - > payload ;
uint32_t src_addr = ntohl ( ipv4 - > source ) ;
uint32_t dst_addr = ntohl ( ipv4 - > destination ) ;
uint16_t length = ntohs ( ipv4 - > length ) ;
char src_ip [ 16 ] ;
char dst_ip [ 16 ] ;
ip_ntoa ( src_addr , src_ip ) ;
ip_ntoa ( dst_addr , dst_ip ) ;
fprintf ( tty , " IP packet [%s → %s] length=%d bytes \n " ,
src_ip , dst_ip , length ) ;
struct udp_packet * udp = ( struct udp_packet * ) ipv4 - > payload ;
uint16_t src_port = ntohs ( udp - > source_port ) ;
uint16_t dst_port = ntohs ( udp - > destination_port ) ;
uint16_t udp_len = ntohs ( udp - > length ) ;
fprintf ( tty , " UDP [%d → %d] length=%d bytes \n " ,
src_port , dst_port , udp_len ) ;
struct dns_packet * dns = ( struct dns_packet * ) udp - > payload ;
uint16_t dns_questions = ntohs ( dns - > questions ) ;
uint16_t dns_answers = ntohs ( dns - > answers ) ;
fprintf ( tty , " DNS - %d queries, %d answers \n " ,
dns_questions , dns_answers ) ;
fprintf ( tty , " Queries: \n " ) ;
int offset = sizeof ( struct dns_packet ) ;
int queries = 0 ;
uint8_t * bytes = ( uint8_t * ) dns ;
while ( queries < dns_questions ) {
offset = print_dns_name ( tty , dns , offset ) ;
uint16_t * d = ( uint16_t * ) & bytes [ offset ] ;
fprintf ( tty , " - Type: %4x %4x \n " , ntohs ( d [ 0 ] ) , ntohs ( d [ 1 ] ) ) ;
offset + = 4 ;
queries + + ;
}
fprintf ( tty , " Answers: \n " ) ;
int answers = 0 ;
while ( answers < dns_answers ) {
offset = print_dns_name ( tty , dns , offset ) ;
uint16_t * d = ( uint16_t * ) & bytes [ offset ] ;
fprintf ( tty , " - Type: %4x %4x; " , ntohs ( d [ 0 ] ) , ntohs ( d [ 1 ] ) ) ;
offset + = 4 ;
uint32_t * t = ( uint32_t * ) & bytes [ offset ] ;
fprintf ( tty , " TTL: %d; " , ntohl ( t [ 0 ] ) ) ;
offset + = 4 ;
uint16_t * l = ( uint16_t * ) & bytes [ offset ] ;
int _l = ntohs ( l [ 0 ] ) ;
fprintf ( tty , " len: %d; " , _l ) ;
offset + = 2 ;
if ( _l = = 4 ) {
uint32_t * i = ( uint32_t * ) & bytes [ offset ] ;
char ip [ 16 ] ;
ip_ntoa ( ntohl ( i [ 0 ] ) , ip ) ;
fprintf ( tty , " Address: %s \n " , ip ) ;
} else {
if ( ntohs ( d [ 0 ] ) = = 5 ) {
fprintf ( tty , " CNAME: " ) ;
print_dns_name ( tty , dns , offset ) ;
fprintf ( tty , " \n " ) ;
} else {
fprintf ( tty , " dunno \n " ) ;
}
}
offset + = _l ;
answers + + ;
}
}
2014-05-07 09:14:05 +04:00
static void rtl_irq_handler ( struct regs * r ) {
uint16_t status = inports ( rtl_iobase + RTL_PORT_ISR ) ;
outports ( rtl_iobase + RTL_PORT_ISR , status ) ;
irq_ack ( rtl_irq ) ;
if ( status & 0x01 | | status & 0x02 ) {
/* Receive */
while ( ( inportb ( rtl_iobase + RTL_PORT_CMD ) & 0x01 ) = = 0 ) {
int offset = cur_rx % 0x2000 ;
#if 0
uint16_t buf_addr = inports ( rtl_iobase + RTL_PORT_RXADDR ) ;
uint16_t buf_ptr = inports ( rtl_iobase + RTL_PORT_RXPTR ) ;
uint8_t cmd = inportb ( rtl_iobase + RTL_PORT_CMD ) ;
# endif
uint32_t * buf_start = ( uint32_t * ) ( ( uintptr_t ) rtl_rx_buffer + offset ) ;
uint32_t rx_status = buf_start [ 0 ] ;
int rx_size = rx_status > > 16 ;
if ( rx_status & ( 0x0020 | 0x0010 | 0x0004 | 0x0002 ) ) {
debug_print ( WARNING , " rx error :( " ) ;
} else {
uint8_t * buf_8 = ( uint8_t * ) & ( buf_start [ 1 ] ) ;
2014-05-08 10:08:34 +04:00
last_packet = buf_8 ;
2014-05-07 09:14:05 +04:00
}
cur_rx = ( cur_rx + rx_size + 4 + 3 ) & ~ 3 ;
outports ( rtl_iobase + RTL_PORT_RXPTR , cur_rx - 16 ) ;
}
2014-05-08 10:08:34 +04:00
wakeup_queue ( rx_wait ) ;
2014-05-07 09:14:05 +04:00
}
if ( status & 0x08 | | status & 0x04 ) {
2014-05-07 10:29:17 +04:00
unsigned int i = inportl ( rtl_iobase + RTL_PORT_TXSTAT + 4 * dirty_tx ) ;
2014-05-09 06:29:23 +04:00
( void ) i ;
2014-05-07 10:29:17 +04:00
dirty_tx + + ;
if ( dirty_tx = = 5 ) dirty_tx = 0 ;
2014-05-07 09:14:05 +04:00
}
}
DEFINE_SHELL_FUNCTION ( rtl , " rtl8139 experiments " ) {
if ( rtl_device_pci ) {
fprintf ( tty , " Located an RTL 8139: 0x%x \n " , rtl_device_pci ) ;
uint16_t command_reg = pci_read_field ( rtl_device_pci , PCI_COMMAND , 4 ) ;
fprintf ( tty , " COMMAND register before: 0x%4x \n " , command_reg ) ;
if ( command_reg & ( 1 < < 2 ) ) {
fprintf ( tty , " Bus mastering already enabled. \n " ) ;
} else {
command_reg | = ( 1 < < 2 ) ; /* bit 2 */
fprintf ( tty , " COMMAND register after: 0x%4x \n " , command_reg ) ;
pci_write_field ( rtl_device_pci , PCI_COMMAND , 4 , command_reg ) ;
command_reg = pci_read_field ( rtl_device_pci , PCI_COMMAND , 4 ) ;
fprintf ( tty , " COMMAND register after: 0x%4x \n " , command_reg ) ;
}
rtl_irq = pci_read_field ( rtl_device_pci , PCI_INTERRUPT_LINE , 1 ) ;
fprintf ( tty , " Interrupt Line: %x \n " , rtl_irq ) ;
irq_install_handler ( rtl_irq , rtl_irq_handler ) ;
uint32_t rtl_bar0 = pci_read_field ( rtl_device_pci , PCI_BAR0 , 4 ) ;
uint32_t rtl_bar1 = pci_read_field ( rtl_device_pci , PCI_BAR1 , 4 ) ;
fprintf ( tty , " BAR0: 0x%8x \n " , rtl_bar0 ) ;
fprintf ( tty , " BAR1: 0x%8x \n " , rtl_bar1 ) ;
rtl_iobase = 0x00000000 ;
if ( rtl_bar0 & 0x00000001 ) {
rtl_iobase = rtl_bar0 & 0xFFFFFFFC ;
} else {
fprintf ( tty , " This doesn't seem right! RTL8139 should be using an I/O BAR; this looks like a memory bar. " ) ;
}
fprintf ( tty , " RTL iobase: 0x%x \n " , rtl_iobase ) ;
2014-05-08 10:08:34 +04:00
rx_wait = list_create ( ) ;
2014-05-07 09:14:05 +04:00
fprintf ( tty , " Determining mac address... \n " ) ;
2014-05-14 11:13:36 +04:00
for ( int i = 0 ; i < 6 ; + + i ) {
mac [ i ] = inports ( rtl_iobase + RTL_PORT_MAC + i ) ;
}
2014-05-07 09:14:05 +04:00
fprintf ( tty , " %2x:%2x:%2x:%2x:%2x:%2x \n " , mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
fprintf ( tty , " Enabling RTL8139. \n " ) ;
outportb ( rtl_iobase + RTL_PORT_CONFIG , 0x0 ) ;
fprintf ( tty , " Resetting RTL8139. \n " ) ;
outportb ( rtl_iobase + RTL_PORT_CMD , 0x10 ) ;
while ( ( inportb ( rtl_iobase + 0x37 ) & 0x10 ) ! = 0 ) { }
fprintf ( tty , " Done resetting RTL8139. \n " ) ;
2014-05-07 11:17:31 +04:00
for ( int i = 0 ; i < 5 ; + + i ) {
2014-05-07 09:14:05 +04:00
rtl_tx_buffer [ i ] = ( void * ) kvmalloc_p ( 0x1000 , & rtl_tx_phys [ i ] ) ;
for ( int j = 0 ; j < 60 ; + + j ) {
rtl_tx_buffer [ i ] [ j ] = 0xF0 ;
}
}
2014-05-07 09:38:21 +04:00
rtl_rx_buffer = ( uint8_t * ) kvmalloc_p ( 0x3000 , & rtl_rx_phys ) ;
2014-05-07 09:14:05 +04:00
memset ( rtl_rx_buffer , 0x00 , 0x3000 ) ;
fprintf ( tty , " Buffers: \n " ) ;
2014-05-07 09:38:21 +04:00
fprintf ( tty , " rx 0x%x [phys 0x%x and 0x%x and 0x%x] \n " , rtl_rx_buffer , rtl_rx_phys , map_to_physical ( ( uintptr_t ) rtl_rx_buffer + 0x1000 ) , map_to_physical ( ( uintptr_t ) rtl_rx_buffer + 0x2000 ) ) ;
2014-05-07 09:14:05 +04:00
2014-05-07 11:17:31 +04:00
for ( int i = 0 ; i < 5 ; + + i ) {
2014-05-07 09:38:21 +04:00
fprintf ( tty , " tx 0x%x [phys 0x%x] \n " , rtl_tx_buffer [ i ] , rtl_tx_phys [ i ] ) ;
2014-05-07 09:14:05 +04:00
}
fprintf ( tty , " Initializing receive buffer. \n " ) ;
outportl ( rtl_iobase + RTL_PORT_RBSTART , rtl_rx_phys ) ;
fprintf ( tty , " Enabling IRQs. \n " ) ;
outports ( rtl_iobase + RTL_PORT_IMR ,
0x8000 | /* PCI error */
0x4000 | /* PCS timeout */
0x40 | /* Rx FIFO over */
0x20 | /* Rx underrun */
0x10 | /* Rx overflow */
0x08 | /* Tx error */
2014-05-07 10:29:17 +04:00
0x04 | /* Tx okay */
2014-05-07 09:14:05 +04:00
0x02 | /* Rx error */
0x01 /* Rx okay */
) ; /* TOK, ROK */
fprintf ( tty , " Configuring transmit \n " ) ;
outportl ( rtl_iobase + RTL_PORT_TCR ,
0
) ;
fprintf ( tty , " Configuring receive buffer. \n " ) ;
outportl ( rtl_iobase + RTL_PORT_RCR ,
( 0 ) | /* 8K receive */
0x08 | /* broadcast */
0x01 /* all physical */
) ;
fprintf ( tty , " Enabling receive and transmit. \n " ) ;
outportb ( rtl_iobase + RTL_PORT_CMD , 0x08 | 0x04 ) ;
fprintf ( tty , " Resetting rx stats \n " ) ;
outportl ( rtl_iobase + RTL_PORT_RXMISS , 0 ) ;
2014-05-14 12:23:12 +04:00
int next_tx = 0 ;
2014-05-14 09:09:15 +04:00
{
fprintf ( tty , " Sending DHCP discover \n " ) ;
2014-05-14 12:23:12 +04:00
size_t packet_size = write_dhcp_packet ( rtl_tx_buffer [ next_tx ] ) ;
outportl ( rtl_iobase + RTL_PORT_TXBUF + 4 * next_tx , rtl_tx_phys [ next_tx ] ) ;
outportl ( rtl_iobase + RTL_PORT_TXSTAT + 4 * next_tx , packet_size ) ;
2014-05-07 09:14:05 +04:00
2014-05-14 12:23:12 +04:00
next_tx + + ;
if ( next_tx = = 4 ) {
next_tx = 0 ;
}
2014-05-14 09:09:15 +04:00
}
2014-05-07 09:14:05 +04:00
2014-05-14 09:09:15 +04:00
sleep_on ( rx_wait ) ;
2014-05-07 09:14:05 +04:00
2014-05-09 06:29:23 +04:00
{
2014-05-14 09:09:15 +04:00
struct ethernet_packet * eth = ( struct ethernet_packet * ) last_packet ;
uint16_t eth_type = ntohs ( eth - > type ) ;
fprintf ( tty , " Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x) \n " ,
eth - > source [ 0 ] , eth - > source [ 1 ] , eth - > source [ 2 ] ,
eth - > source [ 3 ] , eth - > source [ 4 ] , eth - > source [ 5 ] ,
eth - > destination [ 0 ] , eth - > destination [ 1 ] , eth - > destination [ 2 ] ,
eth - > destination [ 3 ] , eth - > destination [ 4 ] , eth - > destination [ 5 ] ,
eth_type ) ;
struct ipv4_packet * ipv4 = ( struct ipv4_packet * ) eth - > payload ;
2014-05-09 06:29:23 +04:00
uint32_t src_addr = ntohl ( ipv4 - > source ) ;
uint32_t dst_addr = ntohl ( ipv4 - > destination ) ;
uint16_t length = ntohs ( ipv4 - > length ) ;
2014-05-14 09:59:36 +04:00
char src_ip [ 16 ] ;
char dst_ip [ 16 ] ;
ip_ntoa ( src_addr , src_ip ) ;
ip_ntoa ( dst_addr , dst_ip ) ;
fprintf ( tty , " IP packet [%s → %s] length=%d bytes \n " ,
src_ip , dst_ip , length ) ;
2014-05-09 06:29:23 +04:00
2014-05-14 09:09:15 +04:00
struct udp_packet * udp = ( struct udp_packet * ) ipv4 - > payload ; ;
2014-05-09 06:29:23 +04:00
uint16_t src_port = ntohs ( udp - > source_port ) ;
uint16_t dst_port = ntohs ( udp - > destination_port ) ;
uint16_t udp_len = ntohs ( udp - > length ) ;
fprintf ( tty , " UDP [%d → %d] length=%d bytes \n " ,
src_port , dst_port , udp_len ) ;
2014-05-14 09:09:15 +04:00
struct dhcp_packet * dhcp = ( struct dhcp_packet * ) udp - > payload ;
2014-05-09 06:29:23 +04:00
uint32_t yiaddr = ntohl ( dhcp - > yiaddr ) ;
2014-05-14 09:59:36 +04:00
char yiaddr_ip [ 16 ] ;
ip_ntoa ( yiaddr , yiaddr_ip ) ;
fprintf ( tty , " DHCP Offer: %s \n " , yiaddr_ip ) ;
2014-05-09 06:29:23 +04:00
}
2014-05-07 09:14:05 +04:00
2014-05-14 09:09:15 +04:00
{
fprintf ( tty , " Sending DNS query... \n " ) ;
2014-05-14 12:44:31 +04:00
uint8_t queries [ ] = {
3 , ' i ' , ' r ' , ' c ' ,
8 , ' f ' , ' r ' , ' e ' , ' e ' , ' n ' , ' o ' , ' d ' , ' e ' ,
3 , ' n ' , ' e ' , ' t ' ,
0 ,
0x00 , 0x01 , /* A */
0x00 , 0x01 , /* IN */
} ;
size_t packet_size = write_dns_packet ( rtl_tx_buffer [ next_tx ] , sizeof ( queries ) , queries ) ;
2014-05-07 10:29:17 +04:00
2014-05-14 12:23:12 +04:00
outportl ( rtl_iobase + RTL_PORT_TXBUF + 4 * next_tx , rtl_tx_phys [ next_tx ] ) ;
outportl ( rtl_iobase + RTL_PORT_TXSTAT + 4 * next_tx , packet_size ) ;
next_tx + + ;
if ( next_tx = = 4 ) {
next_tx = 0 ;
}
2014-05-14 09:09:15 +04:00
}
2014-05-07 10:29:17 +04:00
2014-05-08 10:08:34 +04:00
sleep_on ( rx_wait ) ;
2014-05-14 12:44:31 +04:00
parse_dns_response ( tty , last_packet ) ;
2014-05-07 10:29:17 +04:00
2014-05-09 06:29:23 +04:00
{
2014-05-14 12:44:31 +04:00
fprintf ( tty , " Sending DNS query... \n " ) ;
uint8_t queries [ ] = {
7 , ' n ' , ' y ' , ' a ' , ' n ' , ' c ' , ' a ' , ' t ' ,
5 , ' d ' , ' a ' , ' k ' , ' k ' , ' o ' ,
2 , ' u ' , ' s ' ,
0 ,
0x00 , 0x01 , /* A */
0x00 , 0x01 , /* IN */
} ;
2014-05-09 06:29:23 +04:00
2014-05-14 12:44:31 +04:00
size_t packet_size = write_dns_packet ( rtl_tx_buffer [ next_tx ] , sizeof ( queries ) , queries ) ;
2014-05-09 06:29:23 +04:00
2014-05-14 12:44:31 +04:00
outportl ( rtl_iobase + RTL_PORT_TXBUF + 4 * next_tx , rtl_tx_phys [ next_tx ] ) ;
outportl ( rtl_iobase + RTL_PORT_TXSTAT + 4 * next_tx , packet_size ) ;
2014-05-14 10:56:54 +04:00
2014-05-14 12:44:31 +04:00
next_tx + + ;
if ( next_tx = = 4 ) {
next_tx = 0 ;
2014-05-14 10:56:54 +04:00
}
}
2014-05-07 10:29:17 +04:00
2014-05-14 12:44:31 +04:00
sleep_on ( rx_wait ) ;
parse_dns_response ( tty , last_packet ) ;
2014-05-07 09:14:05 +04:00
} else {
return - 1 ;
}
return 0 ;
}
static int init ( void ) {
BIND_SHELL_FUNCTION ( rtl ) ;
pci_scan ( & find_rtl , - 1 , & rtl_device_pci ) ;
if ( ! rtl_device_pci ) {
debug_print ( ERROR , " No RTL 8139 found? " ) ;
return 1 ;
}
return 0 ;
}
static int fini ( void ) {
return 0 ;
}
MODULE_DEF ( rtl , init , fini ) ;
MODULE_DEPENDS ( debugshell ) ;