diff --git a/XFX.sln b/XFX.sln index b55d17f..1cffc00 100644 --- a/XFX.sln +++ b/XFX.sln @@ -21,7 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libSystem.Windows", "src\li EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xnbbuild", "src\xnbbuild\xnbbuild.vcxproj", "{E5F1599D-C9FE-4EFB-97B6-13B46D4A1E35}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsocket", "libsocket\libsocket.vcxproj", "{FC85E968-A227-460F-858B-06A3581A65E0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsocket", "src\libsocket\libsocket.vcxproj", "{FC85E968-A227-460F-858B-06A3581A65E0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/include/System/Types.h b/include/System/Types.h index fbd12e9..a8837e8 100644 --- a/include/System/Types.h +++ b/include/System/Types.h @@ -40,6 +40,9 @@ namespace System #define __attribute__(x) #endif +// Structure packing +#define PACKED __attribute__((packed)) + // Aligning Data types // #define ALIGNED4 __attribute__((aligned (4))) @@ -54,4 +57,6 @@ namespace System #define NONNULL(x...) __attribute__((nonnull(x))) #endif +#define DEPRECATED __attribute__((deprecated)) + #endif //_SYSTEM_TYPES_ diff --git a/libsocket/libsocket.vcxproj b/src/libsocket/libsocket.vcxproj similarity index 72% rename from libsocket/libsocket.vcxproj rename to src/libsocket/libsocket.vcxproj index 272b019..37a2797 100644 --- a/libsocket/libsocket.vcxproj +++ b/src/libsocket/libsocket.vcxproj @@ -37,7 +37,12 @@ libsocket.a - WIN32;_DEBUG;$(NMakePreprocessorDefinitions) + ENABLE_XBOX + C:\cygwin\usr\local\openxdk\include;C:\cygwin\usr\local\openxdk\i386-pc-xbox\include;C:\cygwin\usr\local\openxdk\include\SDL;..\..\include;$(NMakeIncludeSearchPath) + make all 2>&1 | sed -e %27s/\(\w\+\):\([0-9]\+\):/\1(\2):/%27 + make rebuild 2>&1 | sed -e %27s/\(\w\+\):\([0-9]\+\):/\1(\2):/%27 + make clean 2>&1 | sed -e %27s/\(\w\+\):\([0-9]\+\):/\1(\2):/%27 + C:\cygwin\usr\include;C:\cygwin\usr\local\openxdk\i386-pc-xbox\include;C:\cygwin\usr\local\openxdk\include;C:\cygwin\usr\local\openxdk\include\SDL;$(SolutionDir)include libsocket.a @@ -47,7 +52,9 @@ + + @@ -55,11 +62,19 @@ + + + + + + + + diff --git a/libsocket/libsocket.vcxproj.filters b/src/libsocket/libsocket.vcxproj.filters similarity index 72% rename from libsocket/libsocket.vcxproj.filters rename to src/libsocket/libsocket.vcxproj.filters index 4c21f62..d8261bc 100644 --- a/libsocket/libsocket.vcxproj.filters +++ b/src/libsocket/libsocket.vcxproj.filters @@ -54,5 +54,31 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/libsocket/src/addr2ascii.c b/src/libsocket/src/addr2ascii.c similarity index 100% rename from libsocket/src/addr2ascii.c rename to src/libsocket/src/addr2ascii.c diff --git a/src/libsocket/src/arp.c b/src/libsocket/src/arp.c new file mode 100644 index 0000000..ac58246 --- /dev/null +++ b/src/libsocket/src/arp.c @@ -0,0 +1,116 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +#include "ethernet.h" + +#define MIN_ARP_SIZE 28 + + +typedef struct arp_packet { + uint16_t hard_type; + uint16_t prot_type; + uint8_t hard_size; + uint8_t prot_size; + uint16_t op; + ethernet_addr sender_ethernet; + ipv4_addr sender_ipv4; + ethernet_addr target_ethernet; + ipv4_addr target_ipv4; +} PACKED arp_packet; + +enum +{ + ARP_OP_REQUEST = 1, + ARP_OP_REPLY, + ARP_OP_RARP_REQUEST, + ARP_OP_RARP_REPLY +}; + +enum +{ + ARP_HARD_TYPE_ETHERNET = 1 +}; + +typedef struct arp_cache_entry +{ + struct arp_cache_entry *next; + struct arp_cache_entry *all_next; + ipv4_addr ip_addr; + netaddr link_addr; + time_t last_used_time; +} arp_cache_entry; + +// arp cache +static void *arp_table; +static mutex_t arp_table_mutex; +static arp_cache_entry *arp_cache_entries; + +typedef struct arp_wait_request +{ + struct arp_wait_request *next; + ipv4_addr sender_ipaddr; + ipv4_addr ip_addr; + time_t last_attempt_time; + int attempt_count; + void (*callback)(int code, void *, ifnet *, netaddr *); + void *callback_args; + ifnet *i; +} arp_wait_request; + +// list of threads blocked on arp requests +static arp_wait_request *arp_waiters; +static mutex_t arp_wait_mutex; +static event_t arp_wait_event; + +static int arp_cache_compare(void *_e, const void *_key) +{ + arp_cache_entry *e = (arp_cache_entry *)_e; + const ipv4_addr *addr = (const ipv4_addr *)_key; + + return (e->ip_addr == *addr) ? 0 : 1; +} + +static unsigned int arp_cache_hash(void *_e, const void *_key, unsigned int range) +{ + arp_cache_entry *e = (arp_cache_entry *)_e; + const ipv4_addr *key = (const ipv4_addr *)_key; + const ipv4_addr *addr; + + if(e) + addr = &e->ip_addr; + else + addr = key; + + // XXX make this smarter + return ((*addr) ^ (*addr >> 8) ^ (*addr >> 16) ^ (*addr >> 24)) % range; +} + + diff --git a/libsocket/src/ascii2addr.c b/src/libsocket/src/ascii2addr.c similarity index 100% rename from libsocket/src/ascii2addr.c rename to src/libsocket/src/ascii2addr.c diff --git a/src/libsocket/src/cbuf.h b/src/libsocket/src/cbuf.h new file mode 100644 index 0000000..13e73b4 --- /dev/null +++ b/src/libsocket/src/cbuf.h @@ -0,0 +1,80 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _LIB_NET_CBUF_H +#define _LIB_NET_CBUF_H + +#include + +#define CBUF_LEN 2048 + +#define CBUF_FLAG_CHAIN_HEAD 1 +#define CBUF_FLAG_CHAIN_TAIL 2 + +typedef struct cbuf { + struct cbuf *next; + size_t len; + size_t total_len; + void *data; + int flags; + + /* used by the network stack to chain a list of these together */ + struct cbuf *packet_next; + + char dat[CBUF_LEN - 2*sizeof(struct cbuf *) - 2*sizeof(size_t) - sizeof(void *) - sizeof(int)]; +} cbuf; + +int cbuf_init(void); +cbuf *cbuf_get_chain(size_t len); +cbuf *cbuf_get_chain_noblock(size_t len); +void cbuf_free_chain_noblock(cbuf *buf); +void cbuf_free_chain(cbuf *buf); + +size_t cbuf_get_len(cbuf *buf); +void *cbuf_get_ptr(cbuf *buf, size_t offset); +int cbuf_is_contig_region(cbuf *buf, size_t start, size_t end); + +int cbuf_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); +int cbuf_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); + +int cbuf_user_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); +int cbuf_user_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); + +uint16_t cbuf_ones_cksum16(cbuf *chain, size_t offset, size_t len); +uint16_t cbuf_ones_cksum16_2(cbuf *chain, size_t offset, size_t len, void *buf, size_t buf_len); + +cbuf *cbuf_merge_chains(cbuf *chain1, cbuf *chain2); +cbuf *cbuf_duplicate_chain(cbuf *chain, size_t offset, size_t len, size_t leading_space); + +cbuf *cbuf_truncate_head(cbuf *chain, size_t trunc_bytes, bool free_unused); +int cbuf_truncate_tail(cbuf *chain, size_t trunc_bytes, bool free_unused); + +int cbuf_extend_head(cbuf **chain, size_t extend_bytes); +int cbuf_extend_tail(cbuf *chain, size_t extend_bytes); + +void cbuf_test(void); + +#endif diff --git a/src/libsocket/src/detect_ping.c b/src/libsocket/src/detect_ping.c new file mode 100644 index 0000000..3d3a686 --- /dev/null +++ b/src/libsocket/src/detect_ping.c @@ -0,0 +1,269 @@ +//Ping detection (it detects incoming pings, but does not reply to them -only arp-) +//Write here your xbox ip address +//(first 3 numbers should match your PC IP address, last one must be unique on your network) +#define MY_IP_ADDRESS "192.168.0.10" + +#include +#include +#include +#include + +#include +#include "string.h" +#include "stdio.h" +#include + +#include "memory.h" + +#include "pktdrv.h" + + + +struct _arp +{ + //ethernet header (14 bytes) + unsigned char EthDst[6]; //0xFFFFFFFFFFFF=any (broadcast) + unsigned char EthSrc[6]; + unsigned short ProtocolType; //0x0608 (0x08 then 0x06)=IP ARP + //arp header (2+2+1+1+2+6+4+6+4=28 bytes) + unsigned short Hardware; //0x0100 (0x00 then 0x01)=Ethernet (10Mbps) + unsigned short Protocol; //0x0008 (0x08 then 0x00)=IP + unsigned char HardwareAddrLen; //6 (bytes) + unsigned char ProtocolAddrLen; //4 (bytes) + unsigned short Operation; //0x0100 (0x00 then 0x01)=Request 0x0200=Answer + unsigned char SenderHardwareAddr[6]; + unsigned char SenderProtocolAddr[4]; //Sender IP address + unsigned char TargetHardwareAddr[6]; //0 if not known yet + unsigned char TargetProtocolAddr[4]; //Target IP address +}; + +struct _ip +{ + //ethernet header (14 bytes) + unsigned char EthDst[6]; //0xFFFFFFFFFFFF=any (broadcast) + unsigned char EthSrc[6]; + unsigned short ProtocolType; //0x0008 (0x08 then 0x00)=IP + //ip header (8 bytes) + unsigned char Version:4; //4 bits, value 4 + unsigned char HeaderLength:4; //4 bits, value 5 (means 20 bytes) + unsigned char DifferentiatedServices; //0 + unsigned short TotalLength; //0x2000 (0x00 then 0x20)=32 bytes + unsigned short Identifier; //Variant + unsigned short FragmentationFlagOffset;//0 + unsigned char TimeToLive; //128 + unsigned char Protocol; //1 = ICMP (Internet Control Message Protocol) + unsigned short HeaderChecksum; //Variant + unsigned char SrcIPAddr[4]; //Sender IP address + unsigned char DstIPAddr[4]; //Target IP address + //icmp sub-protocol + unsigned char ICMPType; //8 = Echo request + unsigned char ICMPCode; //0 + unsigned short Checksum; //Variant + unsigned short ID; //Variant + unsigned short SequenceNumber; //0 then increments with retries + unsigned char ICMPDataArea[18]; +}; + +static unsigned long counter=0; +static unsigned int packetsize=0; +static unsigned char *packetbuffer; + +unsigned long myipaddress; + +void report(void) +{ + int i; + unsigned char *p; + struct _arp *parp; + struct _ip *pip; + + debugPrint("Received packets : %ld\n",counter); + debugPrint("Last received packet size : %d bytes\n",packetsize); + if (packetsize<100) + { + + p=packetbuffer; + for(i=0;iProtocolType==0x0608)&& + (parp->Operation==0x100) ) + debugPrint("It was an ARP request from %d.%d.%d.%d\n", + parp->SenderProtocolAddr[0], + parp->SenderProtocolAddr[1], + parp->SenderProtocolAddr[2], + parp->SenderProtocolAddr[3]); + + pip=(struct _ip *)packetbuffer; + if ( (pip->ProtocolType==0x0008)&& + (pip->Protocol==1)&& + (pip->ICMPType==8) ) + debugPrint("It was a Ping request from %d.%d.%d.%d!\nPktdrv worked!\n", + pip->SrcIPAddr[0], + pip->SrcIPAddr[1], + pip->SrcIPAddr[2], + pip->SrcIPAddr[3]); + + } +} + +int Pktdrv_Callback(unsigned char *packetaddr, unsigned int size) +{ + //We are either called from a Dpc (if line uncommented in MyPktdrvDpc) + //or from our own code (no need to be reentrant) + + counter++; + packetsize=size; + memcpy(packetbuffer,packetaddr,packetsize); + + return 1; //we declare we have taken the packet (reply 0 if you want keep it for later) +} + +void process_last_packet(void) +{ + struct _ip *pip; + struct _arp *parp; + + parp = (struct _arp *)packetbuffer; + + if ((parp->ProtocolType == 0x608) && (parp->Operation == 0x100)) + { + // It's an ARP request + unsigned char tmp[4]; + unsigned long ltmp; + + memcpy(tmp,parp->TargetProtocolAddr,4); + ltmp = *((unsigned long *)tmp); + + // Are we the target? + if (ltmp == myipaddress) + { + // Yes, build up an ARP response (invert src and dst) + memcpy(parp->EthDst,parp->EthSrc,6); + Pktdrv_GetEthernetAddr(parp->EthSrc); + parp->Operation=0x200; + memcpy(parp->TargetHardwareAddr,parp->SenderHardwareAddr,6); + Pktdrv_GetEthernetAddr(parp->SenderHardwareAddr); + memcpy(parp->TargetProtocolAddr,parp->SenderProtocolAddr,4); + memcpy(parp->SenderProtocolAddr,tmp,4); + + debugPrint("Answering to ARP request now!\n"); + + // As a rule, always wait until number of packet not yet sent goes + // below the number of buffers -ring- you are using to send them + while (Pktdrv_GetQueuedTxPkts() >= 1) { /*wait*/ }; + + // In this sample we only send a reply to a request. It never waits. + Pktdrv_SendPacket(packetbuffer,14+28); + } + } + + pip = (struct _ip *)packetbuffer; + if ((pip->ProtocolType == 0x0008) && + (pip->Protocol == 1) && + (pip->ICMPType == 8)) + { + // It's a Ping request (an IP packet with a ICMP Echo request inside) + unsigned char tmp[4]; + unsigned long ltmp; + + memcpy(tmp,pip->DstIPAddr,4); + ltmp = *((unsigned long *)tmp); + + // Are we the target? + if (ltmp == myipaddress) + { + debugPrint("It's a Ping request from %d.%d.%d.%d!\nPktdrv is working!\n", + pip->SrcIPAddr[0], + pip->SrcIPAddr[1], + pip->SrcIPAddr[2], + pip->SrcIPAddr[3]); + //Here we should build up an answer to the ping request + //Do it yourself as an exercise... + //Caution checksums are tricky to calculate... + } + } +} + +void XBoxStartup(void) +{ + int i,v,n,done=0; + char *p; + unsigned char *p2; + + packetbuffer = (unsigned char *)MmAllocateContiguousMemoryEx( + 1520, + 0, //lowest acceptable + 0xFFFFFFFF, //highest acceptable + 0, //no need to align to specific boundaries multiple + 4); //non cached, non ordered + if (!packetbuffer) return; //don't waste my time! + + // convert IP address string into an unsigned long + p = MY_IP_ADDRESS; + p2 = (unsigned char *)&myipaddress; + + for (i = 0, n = 0, v = 0; i < strlen(p) + 1; i++) + { + if (isdigit(p[i])) + v = v * 10 + p[i] - '0'; + else + if ((p[i] == '.') || (p[i] == '\0')) + { + *p2 = (unsigned char)(v&255); + v = 0; + p2++; + n++; + if (n == 4) break; + } + } + + XInput_Init(); + + if (Pktdrv_Init()) + { + debugPrint("Try to ping your XBOX!\n"); + debugPrint("Press A to show statistics\n"); + debugPrint("Press B to stop program\n"); + + while(!done) + { + //When a ping will come, we will receive an ARP then an IP + //-ARP will ask who has the requested ip address on network + //-We will reply and that will give sender our MAC Address + //-The ping itself (an IP packet) will then come + + if (Pktdrv_ReceivePackets()) + { + //We received at least 1 packet. Process last received packet. + process_last_packet(); + } + + XInput_GetEvents(); + + for (i = 0; i < 4; i++) + { + if(g_Pads[i].PressedButtons.ucAnalogButtons[XPAD_A]) report(); + if(g_Pads[i].PressedButtons.ucAnalogButtons[XPAD_B]) done = 1; + } + }; + + Pktdrv_Quit(); + } + else + debugPrint("Couldn't initialize network packet driver\n"); + + XInput_Quit(); + + MmFreeContiguousMemory(packetbuffer); + + debugPrint("Quitting...\n"); + XSleep(5000); + XReboot(); +} diff --git a/src/libsocket/src/ethernet.h b/src/libsocket/src/ethernet.h new file mode 100644 index 0000000..857c7cc --- /dev/null +++ b/src/libsocket/src/ethernet.h @@ -0,0 +1,52 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _LIB_NET_ETHERNET_H +#define _LIB_NET_ETHERNET_H + +#include + +#include "if.h" +#include "cbuf.h" + +#define PROT_TYPE_IPV4 0x0800 +#define PROT_TYPE_ARP 0x0806 + +#define ETHERNET_HEADER_SIZE (6+6+2) +#define ETHERNET_MAX_SIZE (ETHERNET_HEADER_SIZE+1500) +#define ETHERNET_MIN_SIZE (ETHERNET_HEADER_SIZE+46) + +typedef uint8_t ethernet_addr[6]; + +// not to be called directly, use the ifnet.link_output and link_input +int ethernet_input(cbuf *buf, ifnet *i); +int ethernet_output(cbuf *buf, ifnet *i, netaddr *target, int protocol_type); + +int ethernet_init(void); + +void dump_ethernet_addr(ethernet_addr addr); + +#endif diff --git a/src/libsocket/src/if.h b/src/libsocket/src/if.h new file mode 100644 index 0000000..ee3f570 --- /dev/null +++ b/src/libsocket/src/if.h @@ -0,0 +1,93 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _LIB_NET_IF_H +#define _LIB_NET_IF_H + +#include +#include "net.h" +#include +#include +#include +#include +#include + +typedef struct ifaddr +{ + struct ifaddr *next; + struct ifnet *if_owner; + netaddr addr; + netaddr netmask; + netaddr broadcast; +} ifaddr; + +enum +{ + IF_TYPE_NULL = 0, + IF_TYPE_LOOPBACK, + IF_TYPE_ETHERNET +}; + +typedef struct ifhook +{ + int type; + size_t mtu; + netaddr linkaddr; + void *cookie; + int (*if_input)(void *cookie, void *buf, size_t len); + int (*if_output)(void *cookie, const void *buf, size_t len); +} ifhook; + +typedef int if_id; + +typedef struct ifnet +{ + struct ifnet *next; + const ifhook *hook; + if_id id; + int type; + thread_t *rx_thread; + thread_t *tx_thread; + ifaddr *addr_list; + ifaddr *link_addr; + int (*link_input)(cbuf *buf, struct ifnet *i); + int (*link_output)(cbuf *buf, struct ifnet *i, netaddr *target, int protocol_type); + event_t tx_queue_event; + mutex_t tx_queue_lock; + fixed_queue tx_queue; + uint8_t tx_buf[2048]; + uint8_t rx_buf[2048]; +} ifnet; + +int if_init(void); +ifnet *if_id_to_ifnet(if_id id); +int if_register_interface(const ifhook *hook, ifnet **i); +void if_bind_address(ifnet *i, ifaddr *addr); +void if_bind_link_address(ifnet *i, ifaddr *addr); +int if_boot_interface(ifnet *i); +int if_output(cbuf *b, ifnet *i); + +#endif diff --git a/libsocket/src/inet_addr.c b/src/libsocket/src/inet_addr.c similarity index 100% rename from libsocket/src/inet_addr.c rename to src/libsocket/src/inet_addr.c diff --git a/libsocket/src/inet_lnaof.c b/src/libsocket/src/inet_lnaof.c similarity index 100% rename from libsocket/src/inet_lnaof.c rename to src/libsocket/src/inet_lnaof.c diff --git a/libsocket/src/inet_makeaddr.c b/src/libsocket/src/inet_makeaddr.c similarity index 100% rename from libsocket/src/inet_makeaddr.c rename to src/libsocket/src/inet_makeaddr.c diff --git a/libsocket/src/inet_net_ntop.c b/src/libsocket/src/inet_net_ntop.c similarity index 100% rename from libsocket/src/inet_net_ntop.c rename to src/libsocket/src/inet_net_ntop.c diff --git a/libsocket/src/inet_net_pton.c b/src/libsocket/src/inet_net_pton.c similarity index 100% rename from libsocket/src/inet_net_pton.c rename to src/libsocket/src/inet_net_pton.c diff --git a/libsocket/src/inet_ntoa.c b/src/libsocket/src/inet_ntoa.c similarity index 100% rename from libsocket/src/inet_ntoa.c rename to src/libsocket/src/inet_ntoa.c diff --git a/src/libsocket/src/net.h b/src/libsocket/src/net.h new file mode 100644 index 0000000..7bb73ad --- /dev/null +++ b/src/libsocket/src/net.h @@ -0,0 +1,76 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _LIB_NET_NET_H +#define _LIB_NET_NET_H + +#include + +int net_init(void); +int net_init_postdev(void); + +#define NET_CHATTY 0 + +/* common net stuff */ +typedef struct netaddr { + uint8_t len; + uint8_t type; + uint8_t pad0; + uint8_t pad1; + uint8_t addr[12]; +} netaddr; + +enum { + SOCK_PROTO_NULL = 0, + SOCK_PROTO_UDP, + SOCK_PROTO_TCP +}; + +enum { + ADDR_TYPE_NULL = 0, + ADDR_TYPE_ETHERNET, + ADDR_TYPE_IP +}; + +#define SOCK_FLAG_TIMEOUT 1 + +typedef struct sockaddr { + netaddr addr; + int port; +} sockaddr; + +enum { + IP_PROT_ICMP = 1, + IP_PROT_TCP = 6, + IP_PROT_UDP = 17, +}; + +typedef uint32_t ipv4_addr; +#define NETADDR_TO_IPV4(naddr) (*(ipv4_addr *)(&((&(naddr))->addr[0]))) +#define IPV4_DOTADDR_TO_ADDR(a, b, c, d) \ + (((ipv4_addr)(a) << 24) | (((ipv4_addr)(b) & 0xff) << 16) | (((ipv4_addr)(c) & 0xff) << 8) | ((ipv4_addr)(d) & 0xff)) + +#endif diff --git a/libsocket/src/nsap_addr.c b/src/libsocket/src/nsap_addr.c similarity index 100% rename from libsocket/src/nsap_addr.c rename to src/libsocket/src/nsap_addr.c diff --git a/src/libsocket/src/pktdrv.c b/src/libsocket/src/pktdrv.c new file mode 100644 index 0000000..ac76635 --- /dev/null +++ b/src/libsocket/src/pktdrv.c @@ -0,0 +1,968 @@ +// XBOX low level network interface driver (packet driver) +// ======================================================= +// Minimum capabilites : send and receive ethernet packets +// Based on forcedeth Linux nForce driver + +// Ring of buffers for received packets is handled by driver. +// Ring of buffers for sent packets must be handled by yourself. +// Driver will only handle the ring of descriptors for them. +// i.e Call Pktdrv_SendPacket with a buffer address taken among +// your ring of n buffers in a circular way and always verify +// that Pktdrv_GetQueuedTxPkts() +#include +#include + +#include "string.h" +#include "stdio.h" +#include +#include + +#include "pktdrv.h" + +//#define DISPLAYMSG + +// Defines number of Rx & Tx descriptors, and number of buffers -ring- for received pkts +#define NBBUFF 32 + +extern unsigned long times(void *); + +// temporary dirty interface +extern int something_to_send; +extern unsigned char *packet_to_send; +extern unsigned int size_of_packet_to_send; +extern int Pktdrv_Callback(unsigned char *packetaddr, unsigned int packetsize); + +#define MIN(a,b) (((a) < (b))? (a) : (b)) + +struct s_MyStructures +{ + char MyContext[1]; + unsigned char NbrRxBuffersWithoutCheck; + unsigned char Ethaddr[6]; + unsigned char Ethaddr2[6]; + unsigned char Ethaddr_reversed[6]; + KDPC MyPktdrvDpcObject; + ULONG PktdrvIsrCounter; + KIRQL IrqLevel; + ULONG Vector; + ULONG Speed; + ULONG OldPhyState; + ULONG PhysicalMinusVirtual; // = buffers_physaddr - buffers_addrs; + ULONG NbrRxBuffers; + ULONG RxBufferDesc; //= buffers_addr + 2048; + ULONG RxBufferTail; //= buffers_addr + 2048 + g_s->NbrRxBuffers * 8 - 8; + ULONG RxBufferNext; //= buffers_addr + 2048; //Point to next incoming packet entry + ULONG NbrTxBuffers; + ULONG TxBufferDesc; //= buffers_addr; + ULONG TxBufferLast; //= buffers_addr; //Points to last sent packet(s) to check + ULONG TxBufferNext; //= buffers_addr; //Points to next packet to send entry + ULONG TxBufferTail; //= buffers_addr + 8 * g_s->NbrTxBuffers - 8; + ULONG QueuedTxPkts; +}; + +static int g_running=0; +static struct s_MyStructures *g_s; +static KINTERRUPT s_MyInterruptObject; + +// Types and descriptions coming from +// - ntddk.h (WinXP SP1 DDK) +// - winddk.h (Reactos source) +// - forcedeth.c (Linux NVidia nForce driver) + +/* + * Hardware registers: + */ + +enum +{ + NvRegIrqStatus = 0x000, +#define NVREG_IRQSTAT_BIT0EVENT 0x002 +#define NVREG_IRQSTAT_BIT1EVENT 0x004 +#define NVREG_IRQSTAT_BIT2EVENT 0x008 +#define NVREG_IRQSTAT_MIIEVENT 0x040 +#define NVREG_IRQSTAT_UNKEVENT 0x080 +#define NVREG_IRQSTAT_MASK 0x1FF + + NvRegIrqMask = 0x004, +#define NVREG_IRQ_RX_ERROR 0x0001 +#define NVREG_IRQ_RX 0x0002 +#define NVREG_IRQ_RX_NOBUF 0x0004 +#define NVREG_IRQ_TX_ERROR 0x0008 +#define NVREG_IRQ_TX_OK 0x0010 +#define NVREG_IRQ_TIMER 0x0020 +#define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_RX_FORCED 0x0080 +#define NVREG_IRQ_TX_FORCED 0x0100 +#define NVREG_IRQMASK_THROUGHPUT 0x00DF +#define NVREG_IRQMASK_CPU 0x0040 +#define NVREG_IRQ_TX_ALL 0x0118 +//=(NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED) +#define NVREG_IRQ_RX_ALL 0x0087 +//=(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED) +#define NVREG_IRQ_OTHER 0x0060 +//=(NVREG_IRQ_TIMER|NVREG_IRQ_LINK) +#define NVREG_IRQ_UNKNOWN 0x01FF +//=(~ +// ( +// NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF| +// NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER| +// NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED|NVREG_IRQ_TX_FORCED +// ) +// ) + + NvRegUnknownSetupReg6 = 0x008, +#define NVREG_UNKSETUP6_VAL 3 + +/* + * NVREG_POLL_DEFAULT is the interval length of the timer source on the Pktdrv + * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms + */ + NvRegPollingInterval = 0x00c, +#define NVREG_POLL_DEFAULT_THROUGHPUT 970 +#define NVREG_POLL_DEFAULT_CPU 013 + + NvRegMSIMap0 = 0x020, + NvRegMSIMap1 = 0x024, + NvRegMSIIrqMask = 0x030, +#define NVREG_MSI_VECTOR_0_ENABLED 0x001 + + NvRegMacReset = 0x03c, +#define NVREG_MAC_RESET_ASSERT 0x0F3 + + NvRegDuplexMode = 0x080, +#define NVREG_DUPLEX_MODE_HDFLAG 0x00000002 +#define NVREG_DUPLEX_MODE_FORCEF 0x003B0F3C +#define NVREG_DUPLEX_MODE_FORCEH 0x003B0F3E +#define NVREG_DUPLEX_MODE_FDMASK 0xFFFFFFFD + + NvRegTransmitterControl = 0x084, +#define NVREG_SendCTL_START 0x01 + + NvRegTransmitterStatus = 0x088, +#define NVREG_SendSTAT_BUSY 0x01 + + NvRegPacketFilterFlags = 0x08c, +#define NVREG_PFF_ALWAYS 0x7F0008 +#define NVREG_PFF_PROMISC 0x000080 +#define NVREG_PFF_MYADDR 0x000020 +#define NVREG_PFF_ALWAYS_MYADDR 0x7F0020 + + NvRegOffloadConfig = 0x090, +#define NVREG_OFFLOAD_HOMEPHY 0x601 +#define NVREG_OFFLOAD_NORMAL 0x5EE + + NvRegReceiverControl = 0x094, +#define NVREG_RCVCTL_START 0x01 + + NvRegReceiverStatus = 0x098, +#define NVREG_RCVSTAT_BUSY 0x01 + + NvRegRandomSeed = 0x09c, +#define NVREG_RNDSEED_MASK 0x00FF +#define NVREG_RNDSEED_FORCE 0x7F00 +#define NVREG_RNDSEED_FORCE2 0x2D00 +#define NVREG_RNDSEED_FORCE3 0x7400 + + NvRegUnknownSetupReg1 = 0x0A0, +#define NVREG_UNKSETUP1_VAL 0x16070F + NvRegUnknownSetupReg2 = 0x0A4, +#define NVREG_UNKSETUP2_VAL 0x16 + + NvRegMacAddrA = 0x0A8, + NvRegMacAddrB = 0x0AC, + NvRegMulticastAddrA = 0x0B0, +#define NVREG_MCASTADDRA_FORCE 0x01 + NvRegMulticastAddrB = 0x0B4, + NvRegMulticastMaskA = 0x0B8, + NvRegMulticastMaskB = 0x0BC, + + NvRegPhyInterface = 0x0C0, +#define PHY_RGMII 0x10000000 + + NvRegTxRingPhysAddr = 0x100, + NvRegRxRingPhysAddr = 0x104, + NvRegRingSizes = 0x108, +#define NVREG_RINGSZ_TXSHIFT 0 +#define NVREG_RINGSZ_RXSHIFT 16 + + NvRegUnkTransmitterReg = 0x10c, + + NvRegLinkSpeed = 0x110, +#define NVREG_LINKSPEED_FORCE 0x10000 +#define NVREG_LINKSPEED_10MBPS 1000 +#define NVREG_LINKSPEED_100MBPS 100 +#define NVREG_LINKSPEED_1000MBPS 50 +#define NVREG_LINKSPEED_MASK 0xFFF + + NvRegUnknownSetupReg5 = 0x130, +#define NVREG_UNKSETUP5_BIT31 (1<<31) + NvRegUnknownSetupReg3 = 0x13C, +#define NVREG_UNKSETUP3_VAL1 0x200010 + NvRegUnknownSetupReg7 = 0x140, +#define NVREG_UNKSETUP7_VAL1 0x300010 + + NvRegTxRxControl = 0x144, +#define NVREG_TXRXCTL_KICK 0x0001 +#define NVREG_TXRXCTL_BIT1 0x0002 +#define NVREG_TXRXCTL_BIT2 0x0004 +#define NVREG_TXRXCTL_IDLE 0x0008 +#define NVREG_TXRXCTL_RESET 0x0010 +#define NVREG_TXRXCTL_RXCHECK 0x0400 +#define NVREG_TXRXCTL_DESC_1 0x0000 +#define NVREG_TXRXCTL_DESC_2 0x2100 +#define NVREG_TXRXCTL_DESC_3 0x2200 +#define NVREG_TXRXCTL_VLANSTRIP 0x0040 +#define NVREG_TXRXCTL_VLANINS 0x0080 + + NvRegTxRingPhysAddrHigh = 0x148, + NvRegRxRingPhysAddrHigh = 0x14C, + NvRegMIIStatus = 0x180, +#define NVREG_MIISTAT_ERROR 0x0001 +#define NVREG_MIISTAT_LINKCHANGE 0x0008 +#define NVREG_MIISTAT_MASK 0x000F +#define NVREG_MIISTAT_MASK2 0x000F + + NvRegUnknownSetupReg4 = 0x184, +#define NVREG_UNKSETUP4_VAL 8 + + NvRegAdapterControl = 0x188, +#define NVREG_ADAPTCTL_START 0x02 +#define NVREG_ADAPTCTL_LINKUP 0x04 +#define NVREG_ADAPTCTL_PHYVALID 0x40000 +#define NVREG_ADAPTCTL_RUNNING 0x100000 +#define NVREG_ADAPTCTL_PHYSHIFT 24 + + NvRegMIISpeed = 0x18c, +#define NVREG_MIISPEED_BIT8 (1<<8) +#define NVREG_MIIDELAY 5 + NvRegMIIControl = 0x190, +#define NVREG_MIICTL_INUSE 0x08000 +#define NVREG_MIICTL_WRITE 0x00400 +#define NVREG_MIICTL_ADDRSHIFT 5 + NvRegMIIData = 0x194, + + NvRegWakeUpFlags = 0x200, +#define NVREG_WAKEUPFLAGS_VAL 0x7770 +#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24 +#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16 +#define NVREG_WAKEUPFLAGS_D3SHIFT 12 +#define NVREG_WAKEUPFLAGS_D2SHIFT 8 +#define NVREG_WAKEUPFLAGS_D1SHIFT 4 +#define NVREG_WAKEUPFLAGS_D0SHIFT 0 +#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 +#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 +#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 +#define NVREG_WAKEUPFLAGS_ENABLE 0x1111 + + NvRegPatternCRC = 0x204, + NvRegPatternMask = 0x208, + + NvRegPowerCap = 0x268, +#define NVREG_POWERCAP_D3SUPP (1<<30) +#define NVREG_POWERCAP_D2SUPP (1<<26) +#define NVREG_POWERCAP_D1SUPP (1<<25) + NvRegPowerState = 0x26c, +#define NVREG_POWERSTATE_POWEREDUP 0x8000 +#define NVREG_POWERSTATE_VALID 0x0100 +#define NVREG_POWERSTATE_MASK 0x0003 +#define NVREG_POWERSTATE_D0 0x0000 +#define NVREG_POWERSTATE_D1 0x0001 +#define NVREG_POWERSTATE_D2 0x0002 +#define NVREG_POWERSTATE_D3 0x0003 + + NvRegVlanControl = 0x300, +#define NVREG_VLANCONTROL_ENABLE 0x2000 + + NvRegMSIXMap0 = 0x3E0, + NvRegMSIXMap1 = 0x3E4, + NvRegMSIXIrqStatus = 0x3F0, + + NvRegPowerState2 = 0x600, +#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 +#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 +}; + +#define EEPROM_INDEX_MACADDR 0x101 + +#define FLAG_MASK_V1 0xffff0000 +#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1) + +#define NV_TX_LASTPACKET (1<<16) +#define NV_TX_RETRYERROR (1<<19) +#define NV_TX_FORCED_INTERRUPT (1<<24) +#define NV_TX_DEFERRED (1<<26) +#define NV_TX_CARRIERLOST (1<<27) +#define NV_TX_LATECOLLISION (1<<28) +#define NV_TX_UNDERFLOW (1<<29) +#define NV_TX_ERROR (1<<30) +#define NV_TX_VALID (1<<31) + +#define NV_RX_DESCRIPTORVALID (1<<16) +#define NV_RX_MISSEDFRAME (1<<17) +#define NV_RX_SUBSTRACT1 (1<<18) +#define NV_RX_ERROR1 (1<<23) +#define NV_RX_ERROR2 (1<<24) +#define NV_RX_ERROR3 (1<<25) +#define NV_RX_ERROR4 (1<<26) +#define NV_RX_CRCERR (1<<27) +#define NV_RX_OVERFLOW (1<<28) +#define NV_RX_FRAMINGERR (1<<29) +#define NV_RX_ERROR (1<<30) +#define NV_RX_AVAIL (1<<31) + +// PhyGetLinkState +#define PHY_LINK_RUNNING 0x01 +#define PHY_LINK_100MBPS 0x02 +#define PHY_LINK_10MBPS 0x04 +#define PHY_LINK_FULL_DUPLEX 0x08 +#define PHY_LINK_HALF_DUPLEX 0x10 + +// Register access macros for XBOX +#define BASE 0xFEF00000 +#define REG(x) (*((DWORD *)(BASE+(x)))) +#define REGW(x) (*((WORD *)(BASE+(x)))) +#define REGB(x) (*((BYTE *)(BASE+(x)))) + +typedef enum _MEMORY_CACHING_TYPE_ORIG +{ + MmFrameBufferCached = 2 +} MEMORY_CACHING_TYPE_ORIG; + +typedef enum _MEMORY_CACHING_TYPE +{ + MmNonCached = 0, + MmCached = 1, + MmWriteCombined = MmFrameBufferCached, + MmHardwareCoherentCached, + MmNonCachedUnordered, // IA64 + MmUSWCCached, + MmMaximumCacheType +} MEMORY_CACHING_TYPE; +/* + MmNonCached : The requested memory should not be cached by the processor. + MmCached : The processor should cache the requested memory. + MmWriteCombined : The requested memory should not be cached by the processor, + but writes to the memory can be combined by the processor. +*/ + + + +// Checks for possible received packets +static int PktdrvRecvInterrupt(void) +{ + ULONG p; + ULONG flag; + BOOLEAN fatal; + int handled; + int n=0; + + // Look for next entry in Rx ring and read its flag + while(1) + { + p = g_s->RxBufferNext; + flag = *((ULONG *)(p + 4)); + + if (flag & NV_RX_AVAIL) return n; //we received nothing! + + if ((flag & NV_RX_DESCRIPTORVALID) == 0) + { + // Not a received packet + } + else + { + fatal = FALSE; + + if (flag & NV_RX_ERROR) + { + if (flag & NV_RX_FRAMINGERR) { /* not fatal */ } + if (flag & NV_RX_OVERFLOW) { fatal = TRUE; } + if (flag & NV_RX_CRCERR) { fatal = TRUE; } + if (flag & NV_RX_ERROR4) { fatal = TRUE; } + if (flag & NV_RX_ERROR3) { fatal = TRUE; } + if (flag & NV_RX_ERROR2) { fatal = TRUE; } + if (flag & NV_RX_ERROR1) { fatal = TRUE; } + } + + if (!fatal) + { + //Call user callback and warn that a packet has been received + //Phys Addr of packet is *p + //Length of packet is 1 up to 2046 bytes + //Length = ( (*((ULONG *)(p+4))) & 0x7FF ) + 1 + handled = Pktdrv_Callback( + (unsigned char *)((*((ULONG *)p)) - g_s->PhysicalMinusVirtual), + (unsigned int)(((*((ULONG *)(p + 4))) & 0x7FF ) + 1 )); + + if (!handled) + return n; //We probably lack space up there + else + n++; + } + } + + //Empty the entry + *((ULONG *)(p + 4)) = NV_RX_AVAIL | 2045; + + //Have RxBufferNext Point to next entry in ring + if (g_s->RxBufferNext == g_s->RxBufferTail) //return to start of ring? + g_s->RxBufferNext = g_s->RxBufferDesc; + else + g_s->RxBufferNext += 8; + }; + + return n; +} + +// Detects if Tx ring is full or not +static BOOLEAN PktdrvSendReady(void) +{ + return (g_s->QueuedTxPkts != g_s->NbrTxBuffers); +} + +// Checks for a patcket to send +static void PktdrvSendInterrupt(void) +{ + ULONG p, flag; + + // Before we send any packet, let's check if last packets have been sent + while (g_s->TxBufferLast != g_s->TxBufferNext) + { + p = g_s->TxBufferLast; + flag = *((ULONG *)(p + 4)); + + if ((flag & NV_TX_VALID) == 0) + { + //Packet is gone, reduce counter and check next one. + //Note that errors and actual number of bytes sent + //can be read from flag right now and right here! + //Actual number is higher because of padding... + g_s->QueuedTxPkts--; + + //Let's cleanup + *((ULONG *)p) = 0; + *((ULONG *)(p + 4)) = 0; + + //Have TxBufferLast point to next entry + if (g_s->TxBufferLast == g_s->TxBufferTail) + g_s->TxBufferLast = g_s->TxBufferDesc; + else + g_s->TxBufferLast += 8; + } + else + break; //packet not sent already, we will check later + } +} + +static void PktdrvSendPacket(unsigned char *buffer, int length) +{ + ULONG p; + + if (PktdrvSendReady()) // Do we have room in the Tx ring? + { + // p points to next free entry of Tx ring descriptor + p = g_s->TxBufferNext; + + MmLockUnlockBufferPages( + (ULONG)buffer, + length, + 0); + + *((ULONG *)p) = MmGetPhysicalAddress(buffer); + *((ULONG *)(p + 4)) = (length-1) | NV_TX_VALID | NV_TX_LASTPACKET; + + g_s->QueuedTxPkts++; + + //Have TxBufferNext point to next entry + if (g_s->TxBufferNext == g_s->TxBufferTail) //return to start of ring? + g_s->TxBufferNext = g_s->TxBufferDesc; + else + g_s->TxBufferNext += 8; + + REG(NvRegTxRxControl) = NVREG_TXRXCTL_KICK; + } + else + { + //Tx ring is full + //User should do : while(Xnet_GetQueuedPkts()>=n) { /*wait*/ }; then send pkt + //That will prevent the loss of sent packet right here + //Where n is the number of buffers (ring) where pending outcoming packets are + //stored. In most case n=1 (just one buffer is used to send 1 packet at a time) + } +} + +// Starts Pktdrv +static void PktdrvStartSendRecv(void) +{ + REG(NvRegLinkSpeed) = NVREG_LINKSPEED_FORCE | g_s->Speed; + + REG(NvRegTransmitterControl) = NVREG_SendCTL_START; + REG(NvRegReceiverControl) = NVREG_RCVCTL_START; + + REG(NvRegTxRxControl) = NVREG_TXRXCTL_KICK | NVREG_TXRXCTL_BIT1; +} + +//Stops Pktdrv +static void PktdrvStopSendRecv(void) +{ + int i; + + REG(NvRegLinkSpeed) = 0; + REG(NvRegReceiverControl) = 0; + REG(NvRegTransmitterControl) = 0; + + for (i = 0; i < 500; i++) + { + if (((REGB(NvRegReceiverStatus) & NVREG_RCVSTAT_BUSY) == 0) && + ((REGB(NvRegTransmitterStatus) & NVREG_SendSTAT_BUSY) == 0)) + break; + + KeStallExecutionProcessor(10); //Wait 10 microseconds + } + + REG(NvRegTxRxControl) = NVREG_TXRXCTL_BIT2; + + for (i = 0; i < 100000; i++) + { + if (REGB(NvRegTxRxControl) & NVREG_TXRXCTL_IDLE) break; + + KeStallExecutionProcessor(10); + } + + REG(NvRegTxRxControl) = 0; +} + +// Resets Pktdrv +static void PktdrvReset(void) +{ + PktdrvStopSendRecv(); + + REG(NvRegTxRxControl) = NVREG_TXRXCTL_RESET; + KeStallExecutionProcessor(10); // 10 microseconds of busy-wait + + REG(NvRegTxRxControl) = 0; + KeStallExecutionProcessor(10); + + REG(NvRegUnknownSetupReg4) = 0; + REG(NvRegIrqMask) = 0; + REG(NvRegWakeUpFlags) = 0; + REG(NvRegUnknownSetupReg6) = 0; + REG(NvRegTxRingPhysAddr) = 0; + REG(NvRegRxRingPhysAddr) = 0; + REG(NvRegUnkTransmitterReg) = 0; + REG(NvRegLinkSpeed) = 0; + + REG(NvRegTransmitterStatus) = REG(NvRegTransmitterStatus); + REG(NvRegReceiverStatus) = REG(NvRegReceiverStatus); + REG(NvRegMIIStatus) = REG(NvRegMIIStatus); + REG(NvRegIrqStatus) = REG(NvRegIrqStatus); +} + +// Checks possible speed or duplex mode change +static void PktdrvMiiInterrupt(int mode) +{ + // Verifies if speed or duplex mode changed + // mode=1 -> startup mode (calls PhyGetLinkState(0)) + // (used at startup, before Pktdrv driver is started) + // mode=0 -> running mode (calls PhyGetLinkState(1)) + // (used in interrupt, while Pktdrv driver is running) + ULONG state,dummy; + + mode &= 1; // only 0 or 1 is accepted + dummy = REG(NvRegAdapterControl); // just read it + state = PhyGetLinkState(1 - mode); + + if ((mode == 0) && (state == g_s->OldPhyState)) return; // All is ok, remain silent + + //We want details (startup) or state changed (both modes) +#ifdef DISPLAYMSG + debugPrint("Transceiver link state :\n"); + + if (state & PHY_LINK_RUNNING) + debugPrint(" Running at "); + else + debugPrint(" NOT running at "); + + if (state & PHY_LINK_100MBPS) + debugPrint("100 Mbps "); + else + if (state & PHY_LINK_10MBPS) + debugPrint("10 Mbps "); + else + debugPrint("unknown speed "); + + if (state & PHY_LINK_FULL_DUPLEX) + debugPrint("in full duplex mode\n"); + else + if (state & PHY_LINK_HALF_DUPLEX) + debugPrint("in half duplex mode\n"); + else + debugPrint("in unknown duplex mode\n"); +#endif + if (mode == 0) PktdrvStopSendRecv(); // Pktdrv is running. Stop it. + + if (state & PHY_LINK_10MBPS) // update Speed member in structure + g_s->Speed = NVREG_LINKSPEED_10MBPS; // decimal value 1000!!! + else + g_s->Speed = NVREG_LINKSPEED_100MBPS; // decimal value 100 + + if (state & PHY_LINK_FULL_DUPLEX) // update mode in Pktdrv register + REG(NvRegDuplexMode) &= NVREG_DUPLEX_MODE_FDMASK; + else + REG(NvRegDuplexMode) |= NVREG_DUPLEX_MODE_HDFLAG; + + if (mode == 0) PktdrvStartSendRecv(); // Mode changed. Restart Pktdrv. + // This function will read g_s->Speed and program speed link register. + + g_s->OldPhyState = state; +} + +static BOOLEAN __stdcall MyPktdrvIsr(PKINTERRUPT Interrupt, PVOID ServiceContext) +{ + REG(NvRegIrqMask) = 0; + + if (g_running) + { + KeInsertQueueDpc(&g_s->MyPktdrvDpcObject,NULL,NULL); + g_s->PktdrvIsrCounter++; + } + + return TRUE; +} + +static void __stdcall MyPktdrvDpc +( + PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2 +) +{ + // DPCs allow to use non reentrant procedures (called sequentially, FOR SURE). + // CAUTION : if you use fpu in DPC you have to save & restore yourself fpu state!!! + // (fpu=floating point unit, i.e the coprocessor executing floating point opcodes) + + ULONG irq_status; + ULONG mii_status; + + if (g_running == 0) return; + + mii_status = 0; + irq_status = NVREG_IRQSTAT_BIT0EVENT | + NVREG_IRQSTAT_BIT1EVENT | + NVREG_IRQSTAT_BIT2EVENT | + NVREG_IRQSTAT_UNKEVENT; + + while (irq_status) + { + if (irq_status & NVREG_IRQSTAT_MIIEVENT) PktdrvMiiInterrupt(0); + REG(NvRegMIIStatus) = mii_status; + REG(NvRegIrqStatus) = irq_status; +//uncomment this line if you want your callback to be called as soon as packet arrived +// PktdrvRecvInterrupt(); //Check if we received packets // (let them stock up) + PktdrvSendInterrupt(); //Check if we have a packet to send + + if (irq_status & NVREG_IRQSTAT_BIT1EVENT) + { + REG(NvRegTxRxControl) = NVREG_TXRXCTL_BIT1; + } + + mii_status = REG(NvRegMIIStatus); + irq_status = REG(NvRegIrqStatus); + }; + + REG(NvRegIrqMask) = NVREG_IRQ_LINK | + NVREG_IRQ_TX_OK | + NVREG_IRQ_TX_ERROR | + NVREG_IRQ_RX_NOBUF | + NVREG_IRQ_RX | + NVREG_IRQ_RX_ERROR; + + return; +} + +void Pktdrv_Quit(void) +{ + if (g_running == 0) return; + + g_running = 0; + + PktdrvStopSendRecv(); + PktdrvReset(); + KeDisconnectInterrupt(&s_MyInterruptObject); + + MmFreeContiguousMemory((void *)g_s->TxBufferDesc); + + free(g_s); +} + +// Returns 1 if everything is ok +int Pktdrv_Init(void) +{ + int n,len,type; + ULONG buffers_addr; + ULONG buffers_physaddr; + ULONG status; + ULONG buffers_total_size; + ULONG p,p2; + ULONG RandomValue; + + if (g_running == 1) return 1; + + g_s = (struct s_MyStructures *)malloc(sizeof(struct s_MyStructures)); + + // g_s holds the various needed structures + if (!g_s) + { + debugPrint("Can't allocate global structure.\n"); + return 0; + } + + g_s->Vector = HalGetInterruptVector(4,&g_s->IrqLevel); + + KeInitializeDpc(&g_s->MyPktdrvDpcObject,&MyPktdrvDpc,&g_s->MyContext); + + KeInitializeInterrupt(&s_MyInterruptObject, + &MyPktdrvIsr, + &g_s->MyContext, + g_s->Vector, + g_s->IrqLevel, + LevelSensitive, + TRUE); + + PktdrvReset(); + + g_s->NbrRxBuffersWithoutCheck = NBBUFF; //Total buffers = NBBUFF+2 (Tx&Rx Descriptors) + + n = g_s->NbrRxBuffersWithoutCheck; + g_s->NbrRxBuffers = MIN(n,256); + g_s->NbrTxBuffers = MIN(n,256); + + //Rx ring will point to the pool of n allocated buffers + //Tx ring is empty at startup may point to any contiguous buffer physical address + + buffers_total_size = ((n + 1 + 1) << 11); + + //allocates n+1+1 DMA buffers 2048 bytes each + buffers_addr = (ULONG)MmAllocateContiguousMemoryEx( + buffers_total_size, + 0, //lowest acceptable + 0x10000, //highest acceptable + 0, //no need to align to specific boundaries multiple + MmNonCachedUnordered); //4 + + if (!buffers_addr) + buffers_addr=(ULONG)MmAllocateContiguousMemoryEx( + buffers_total_size, + 0, //lowest acceptable + 0xFFFFFFFF, //highest acceptable + 0, //no need to align to specific boundaries multiple + MmNonCachedUnordered); //4 + + if (!buffers_addr) + { + debugPrint("Can't allocate DMA reception buffers\n"); + + free(g_s); + + return 0; + } + + //Write zeroes in first buffer and second buffer (descriptors) + memset((void *)buffers_addr, 0, 4096); + + buffers_physaddr = MmGetPhysicalAddress((void *)buffers_addr); + + g_s->PhysicalMinusVirtual = buffers_physaddr - buffers_addr; + + g_s->RxBufferDesc = buffers_addr + 2048; + g_s->RxBufferNext = buffers_addr + 2048; + g_s->RxBufferTail = buffers_addr + 2048 + g_s->NbrRxBuffers * 8 - 8; + + g_s->TxBufferDesc = buffers_addr; + g_s->TxBufferLast = buffers_addr; + g_s->TxBufferNext = buffers_addr; + g_s->TxBufferTail = buffers_addr + 8 * g_s->NbrTxBuffers - 8; + + p = buffers_addr + 4096 + 2 + g_s->PhysicalMinusVirtual; //Points 1st buffer at offset 2 + p2 = buffers_addr + 2048; + + while(p2 <= g_s->RxBufferTail) + { + *((DWORD *)p2) = p; //Physical address of offset 2 of buffer + *((DWORD *)(p2 + 4)) = NV_RX_AVAIL | 2045; //Makes all Rx buffers available + //2046 bytes available for incoming packet at offset 2 + p2 += 8; + p += 2048; + }; + + //Buffers description : + //1st buffer is a list of n pointers+flags (every 8 bytes) and is Tx ring descriptor + //2nd buffer is a list of n pointers+flags (every 8 bytes) and is Rx ring descriptor + //3rd buffer and following ones are pointed by the Rx ring pointers (at offset 2) + //(n buffers used for packet receiving at startup while Tx ring is all zeroed) + //Total : 1+1+n buffers + //Descriptor is a list of 8 bytes values (a 32 bits physical address + a 32 bits flag) + //The flag has the length (minus one) of available room/received packet/to send packet + //in the lower 11 bits of the 32 bits flag + + len = 0; + ExQueryNonVolatileSetting(EEPROM_INDEX_MACADDR, &type, g_s->Ethaddr, 6, &len); + + if (len != 6) + debugPrint("Can't read ethernet address from EEPROM\n"); +#ifdef DISPLAYMSG + else + debugPrint("EEPROM MacAddress = %02x %02x %02x %02x %02x %02x\n", + g_s->Ethaddr[0], + g_s->Ethaddr[1], + g_s->Ethaddr[2], + g_s->Ethaddr[3], + g_s->Ethaddr[4], + g_s->Ethaddr[5]); +#endif + + g_s->Speed = NVREG_LINKSPEED_100MBPS; + + g_s->Ethaddr_reversed[0] = g_s->Ethaddr[5]; + g_s->Ethaddr_reversed[1] = g_s->Ethaddr[4]; + g_s->Ethaddr_reversed[2] = g_s->Ethaddr[3]; + g_s->Ethaddr_reversed[3] = g_s->Ethaddr[2]; + g_s->Ethaddr_reversed[4] = g_s->Ethaddr[1]; + g_s->Ethaddr_reversed[5] = g_s->Ethaddr[0]; + + //Writing the MAC address (6 bytes ethernet address) + REG(NvRegMacAddrA) = *((DWORD *)&g_s->Ethaddr_reversed[0]); + REG(NvRegMacAddrB) = (ULONG)(*((WORD *)&g_s->Ethaddr_reversed[4])); + + REG(NvRegMulticastMaskA) = 0xFFFFFFFF; + REG(NvRegMulticastMaskB) = 0x0000FFFF; + REG(NvRegMulticastAddrA) = *((DWORD *)&g_s->Ethaddr[0]); //Yes, not reversed! + REG(NvRegMulticastAddrB) = (ULONG)(*((WORD *)&g_s->Ethaddr[4])); + + RandomValue = times(0) + 0x1234 + *((DWORD *)g_s->Ethaddr) + *((WORD *)&g_s->Ethaddr[4]); + + //In case of ethernet colision, random duration pauses are used before retry + REG(NvRegRandomSeed) = (RandomValue & NVREG_RNDSEED_MASK) | NVREG_RNDSEED_FORCE; + + REG(NvRegOffloadConfig) = NVREG_OFFLOAD_NORMAL; //1518 bytes + REG(NvRegPacketFilterFlags) = NVREG_PFF_ALWAYS_MYADDR; + REG(NvRegDuplexMode) = NVREG_DUPLEX_MODE_FORCEH; + + REG(NvRegUnknownSetupReg1) = NVREG_UNKSETUP1_VAL; + REG(NvRegUnknownSetupReg2) = NVREG_UNKSETUP2_VAL; + + //Writing the DMA buffers addresses and sizes + REG(NvRegTxRingPhysAddr) = g_s->TxBufferDesc + g_s->PhysicalMinusVirtual; // 1st buf phys + REG(NvRegRxRingPhysAddr) = g_s->RxBufferDesc + g_s->PhysicalMinusVirtual; // 2nd buf phys + REG(NvRegRingSizes) = ((g_s->NbrRxBuffers - 1) << 16) | (g_s->NbrTxBuffers - 1); + + REG(NvRegUnknownSetupReg7) = NVREG_UNKSETUP7_VAL1; + REG(NvRegUnknownSetupReg3) = NVREG_UNKSETUP7_VAL1; //Yes, Val7 into Reg3! + + REG(NvRegAdapterControl) = (1 << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID; + REG(NvRegMIISpeed) = NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY; + + KeStallExecutionProcessor(50); //50 micro seconds of busy-wait + + g_running=1; + + // XBOX specific (nForce specific) + if (PhyInitialize(0, 0) < 0) // Initialize transceiver + { + debugPrint("PhyInitialize error\n"); + + Pktdrv_Quit(); + + return 0; + } + + REG(NvRegAdapterControl) = NVREG_ADAPTCTL_RUNNING; + + KeStallExecutionProcessor(50); + + PktdrvMiiInterrupt(1); //force display/update of current speed and duplex mode + + PktdrvStartSendRecv(); + + REG(NvRegMIIStatus) = REG(NvRegMIIStatus); + REG(NvRegIrqStatus) = REG(NvRegIrqStatus); + + REG(NvRegUnknownSetupReg4) = NVREG_UNKSETUP4_VAL; + + REG(NvRegIrqMask)= NVREG_IRQ_LINK | + NVREG_IRQ_TX_OK | + NVREG_IRQ_TX_ERROR | + NVREG_IRQ_RX_NOBUF | + NVREG_IRQ_RX | + NVREG_IRQ_RX_ERROR; + + status = KeConnectInterrupt(&s_MyInterruptObject); + + if (status == 0) + { + debugPrint("KeConnectInterrupt error\n"); + + Pktdrv_Quit(); + + return 0; + } +#ifdef DISPLAYMSG + else + debugPrint("Network interruption initialized successfully\n"); +#endif + return 1; +} + +int Pktdrv_ReceivePackets(void) +{ + if (g_running) return PktdrvRecvInterrupt(); //returns nbr of packets accepted by callback + + return 0; +} + +void Pktdrv_SendPacket(unsigned char *buffer,int length) +{ + if (g_running) + { + PktdrvSendInterrupt(); + + // if QueuedTxPkts>=n (n=number of outgoing buffers -ring- in calling app) + // then packet will not be sent (app has to wait until QueuedTxPktsEthaddr, 6); + } +} + +int Pktdrv_GetQueuedTxPkts(void) +{ + if (g_running) + { + PktdrvSendInterrupt(); // detects any sent packet and updates QueuedTxPkts + + return g_s->QueuedTxPkts; + } + else + return 0; +} diff --git a/src/libsocket/src/pktdrv.h b/src/libsocket/src/pktdrv.h new file mode 100644 index 0000000..888527c --- /dev/null +++ b/src/libsocket/src/pktdrv.h @@ -0,0 +1,11 @@ +#ifndef _Pktdrv_ +#define _Pktdrv_ + +int Pktdrv_Init(void); +void Pktdrv_Quit(void); +int Pktdrv_ReceivePackets(void); +void Pktdrv_SendPacket(unsigned char *buffer,int length); +void Pktdrv_GetEthernetAddr(unsigned char *address); +int Pktdrv_GetQueuedTxPkts(void); + +#endif diff --git a/libsocket/src/recv.c b/src/libsocket/src/recv.c similarity index 100% rename from libsocket/src/recv.c rename to src/libsocket/src/recv.c diff --git a/libsocket/src/send.c b/src/libsocket/src/send.c similarity index 100% rename from libsocket/src/send.c rename to src/libsocket/src/send.c diff --git a/libsocket/src/sockatmark.c b/src/libsocket/src/sockatmark.c similarity index 100% rename from libsocket/src/sockatmark.c rename to src/libsocket/src/sockatmark.c diff --git a/libsocket/src/sourcefilter.c b/src/libsocket/src/sourcefilter.c similarity index 100% rename from libsocket/src/sourcefilter.c rename to src/libsocket/src/sourcefilter.c