From e234c493b4e5e36ecf980161773eb03b15f26820 Mon Sep 17 00:00:00 2001 From: Tom Lint Date: Tue, 15 Jul 2014 17:22:43 +0200 Subject: [PATCH] Added AFL packet driver Implemented SocketAddress class Fixed Array class --- include/System/Array.h | 48 +- include/System/Net/IPEndPoint.h | 2 +- include/System/Net/SocketAddress.h | 8 +- src/libSystem/SocketAddress.cpp | 96 ++- src/libSystem/detect_ping.c | 269 +++++++ src/libSystem/libSystem.vcxproj | 3 + src/libSystem/libSystem.vcxproj.filters | 9 + src/libSystem/license.txt | 166 ++++ src/libSystem/makefile | 2 +- src/libSystem/pktdrv.c | 968 ++++++++++++++++++++++++ src/libSystem/pktdrv.h | 11 + 11 files changed, 1550 insertions(+), 32 deletions(-) create mode 100644 src/libSystem/detect_ping.c create mode 100644 src/libSystem/license.txt create mode 100644 src/libSystem/pktdrv.c create mode 100644 src/libSystem/pktdrv.h diff --git a/include/System/Array.h b/include/System/Array.h index f7e02ab..5788aa9 100644 --- a/include/System/Array.h +++ b/include/System/Array.h @@ -20,10 +20,10 @@ using namespace System::Collections::Generic; namespace System { /** - * + * Represents a single-dimension array. */ template - class Array : public ICollection, public IEnumerable + class Array : public IEnumerable { private: T* _array; @@ -39,7 +39,8 @@ namespace System public: const int Length; - Array(const int size) : _array(new T[size]), _version(0), Length(size) + Array(const int size) + : _array(new T[size]), _version(0), Length(size) { memset(_array, 0, sizeof(T) * size); } @@ -72,13 +73,10 @@ namespace System { sassert(array != null, String::Format("array; %s", FrameworkResources::ArgumentNull_Generic)); - for(int i = 0, j = index; i < Length; i++) - { - array[j] = _array[i]; - } + memcpy(&array[index], &_array[0], sizeof(T) * Length); } - inline IEnumerator* GetEnumerator() const + inline IEnumerator* GetEnumerator() { return new ArrayEnumerator(this); } @@ -118,8 +116,17 @@ namespace System _version++; } + inline const T& operator[](const int index) const + { + sassert(index > 0 && index < Length, ""); + + return _array[index]; + } + inline T& operator[](const int index) { + sassert(index > 0 && index < Length, ""); + return _array[index]; } @@ -177,7 +184,8 @@ namespace System public: const int Length; - Array(const int size) : _array(new T*[size]), _version(0), Length(size) + Array(const int size) + : _array(new T*[size]), _version(0), Length(size) { memset(_array, 0, sizeof(T *) * size); } @@ -185,10 +193,7 @@ namespace System Array(const Array &obj) : _array(new T*[obj.Length]), _version(obj._version), Length(obj.Length) { - for (int i = 0; i < Length; i++) - { - _array[i] = obj._array[i]; - } + memcpy(_array, obj._array, sizeof(T *) * Length); } ~Array() { delete _array; } @@ -207,10 +212,7 @@ namespace System { sassert(array != null, String::Format("array; %s", FrameworkResources::ArgumentNull_Generic)); - for(int i = 0, j = index; i < Length; i++) - { - array[j] = _array[i]; - } + memcpy(array[index], _array[0], sizeof(T *) * Length); } inline IEnumerator* GetEnumerator() const @@ -242,6 +244,7 @@ namespace System int num = startIndex; int num2 = (startIndex + count) - 1; + while (num < num2) { swap(_array[num], _array[num2]); @@ -252,8 +255,17 @@ namespace System _version++; } - inline T* operator[](const int index) + inline const T*& operator[](const int index) const { + sassert(index > 0 && index < Length, ""); + + return _array[index]; + } + + inline T*& operator[](const int index) + { + sassert(index > 0 && index < Length, ""); + return _array[index]; } diff --git a/include/System/Net/IPEndPoint.h b/include/System/Net/IPEndPoint.h index 8a4cb5d..018a634 100644 --- a/include/System/Net/IPEndPoint.h +++ b/include/System/Net/IPEndPoint.h @@ -36,7 +36,7 @@ namespace System IPEndPoint(const long long address, const int port); IPEndPoint(IPAddress * const address, const int port); - EndPoint * Create(SocketAddress socketAddress); + EndPoint * Create(SocketAddress * const socketAddress); bool Equals(Object const * const obj) const; int GetHashCode() const; SocketAddress * Serialize(); diff --git a/include/System/Net/SocketAddress.h b/include/System/Net/SocketAddress.h index 91b6ae6..96b73cf 100644 --- a/include/System/Net/SocketAddress.h +++ b/include/System/Net/SocketAddress.h @@ -7,6 +7,7 @@ #ifndef _SYSTEM_NET_SOCKETADDRESS_ #define _SYSTEM_NET_SOCKETADDRESS_ +#include #include #include #include @@ -23,13 +24,11 @@ namespace System class SocketAddress : public Object { private: - AddressFamily_t addressFamily; - int bufferSize; + Array data; public: AddressFamily_t getFamily(); int getSize(); - byte operator[](int offset); SocketAddress(AddressFamily_t family); SocketAddress(AddressFamily_t family, int size); @@ -38,6 +37,9 @@ namespace System int GetHashCode() const; static const Type& GetType(); const String ToString(); + + const byte& operator[](const int index) const; + byte& operator[](const int index); }; } } diff --git a/src/libSystem/SocketAddress.cpp b/src/libSystem/SocketAddress.cpp index bb2c408..89fd511 100644 --- a/src/libSystem/SocketAddress.cpp +++ b/src/libSystem/SocketAddress.cpp @@ -25,10 +25,13 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +#include #include #include #include +#include + namespace System { namespace Net @@ -37,24 +40,60 @@ namespace System AddressFamily_t SocketAddress::getFamily() { - return addressFamily; + return (AddressFamily_t)(data[0] + (data[1] << 8)); } int SocketAddress::getSize() { - return bufferSize; + return data.Length; } SocketAddress::SocketAddress(AddressFamily_t family) - : addressFamily(family) + : data(32) { - // TODO: implement remainder + data[0] = (byte)family; + data[1] = (byte)((int)family >> 8); } SocketAddress::SocketAddress(AddressFamily_t family, int size) - : addressFamily(family), bufferSize(size) + : data(size) { - // TODO: implement remainder + sassert(size >= 2, "size is too small"); + + data[0] = (byte)family; + data[1] = (byte)((int)family >> 8); + } + + bool SocketAddress::Equals(Object const * const obj) const + { + SocketAddress* sa = as(obj); + + if (sa != NULL && sa->data.Length == data.Length) + { + for (int i = 0; i < data.Length; i++) + { + if (data[i] != sa->data[i]) + { + return false; + } + } + + return true; + } + + return false; + } + + int SocketAddress::GetHashCode() const + { + int code = 0; + + for (int i = 0; i < data.Length; i++) + { + code += data[i] + i; + } + + return code; } const Type& SocketAddress::GetType() @@ -64,12 +103,51 @@ namespace System const String SocketAddress::ToString() { - // TODO: implement + String af; + + switch ((AddressFamily_t)data[0]) + { + case AddressFamily::InterNetwork: + af = "InterNetwork"; + break; + case AddressFamily::InterNetworkV6: + af = "InterNetworkV6"; + break; + case AddressFamily::Unknown: + af = "Unknown"; + break; + case AddressFamily::Unspecified: + af = "Unspecified"; + break; + } + + int size = data.Length; + String ret = af + ":" + Int32::ToString(size) + ":{"; + + for (int i = 2; i < size; i++) + { + int val = (int)data[i]; + ret = ret + val; + + if (i < size - 1) + { + ret = ret + ","; + } + } + + ret = ret + "}"; + + return(ret); } - byte SocketAddress::operator[](int offset) + const byte& SocketAddress::operator[](const int index) const { - // TODO: implement + return data[index]; + } + + byte& SocketAddress::operator[](const int index) + { + return data[index]; } } } diff --git a/src/libSystem/detect_ping.c b/src/libSystem/detect_ping.c new file mode 100644 index 0000000..3d3a686 --- /dev/null +++ b/src/libSystem/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/libSystem/libSystem.vcxproj b/src/libSystem/libSystem.vcxproj index d4a505d..9ca5f51 100644 --- a/src/libSystem/libSystem.vcxproj +++ b/src/libSystem/libSystem.vcxproj @@ -73,12 +73,14 @@ + + @@ -99,6 +101,7 @@ + diff --git a/src/libSystem/libSystem.vcxproj.filters b/src/libSystem/libSystem.vcxproj.filters index 075c835..18ab09f 100644 --- a/src/libSystem/libSystem.vcxproj.filters +++ b/src/libSystem/libSystem.vcxproj.filters @@ -81,6 +81,12 @@ Source Files\Net + + Source Files + + + Source Files + @@ -122,6 +128,9 @@ Header Files\Net + + Header Files + diff --git a/src/libSystem/license.txt b/src/libSystem/license.txt new file mode 100644 index 0000000..c793e56 --- /dev/null +++ b/src/libSystem/license.txt @@ -0,0 +1,166 @@ + + The Academic Free License + v. 2.0 + +This Academic Free License (the "License") applies to any original work +of authorship (the "Original Work") whose owner (the "Licensor") has +placed the following notice immediately following the copyright notice +for the Original Work: + + *Licensed under the Academic Free License version 2.0* + +1) *Grant of Copyright License.* Licensor hereby grants You a +world-wide, royalty-free, non-exclusive, perpetual, sublicenseable +license to do the following: + + a) to reproduce the Original Work in copies; + + b) to prepare derivative works ("Derivative Works") based upon the + Original Work; + + c) to distribute copies of the Original Work and Derivative Works to + the public; + + d) to perform the Original Work publicly; and + + e) to display the Original Work publicly. + +2) *Grant of Patent License.* Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license, under +patent claims owned or controlled by the Licensor that are embodied in +the Original Work as furnished by the Licensor, to make, use, sell and +offer for sale the Original Work and Derivative Works. + +3) *Grant of Source Code License.* The term "Source Code" means the +preferred form of the Original Work for making modifications to it and +all available documentation describing how to modify the Original Work. +Licensor hereby agrees to provide a machine-readable copy of the Source +Code of the Original Work along with each copy of the Original Work that +Licensor distributes. Licensor reserves the right to satisfy this +obligation by placing a machine-readable copy of the Source Code in an +information repository reasonably calculated to permit inexpensive and +convenient access by You for as long as Licensor continues to distribute +the Original Work, and by publishing the address of that information +repository in a notice immediately following the copyright notice that +applies to the Original Work. + +4) *Exclusions From License Grant. *Neither the names of Licensor, nor +the names of any contributors to the Original Work, nor any of their +trademarks or service marks, may be used to endorse or promote products +derived from this Original Work without express prior written permission +of the Licensor. Nothing in this License shall be deemed to grant any +rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor except as expressly stated herein. No +patent license is granted to make, use, sell or offer to sell +embodiments of any patent claims other than the licensed claims defined +in Section 2. No right is granted to the trademarks of Licensor even if +such marks are included in the Original Work. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different +terms from this License any Original Work that Licensor otherwise would +have a right to license. + +5) This section intentionally omitted. + +6) *Attribution Rights.* You must retain, in the Source Code of any +Derivative Works that You create, all copyright, patent or trademark +notices from the Source Code of the Original Work, as well as any +notices of licensing and any descriptive text identified therein as an +"Attribution Notice." You must cause the Source Code for any Derivative +Works that You create to carry a prominent Attribution Notice reasonably +calculated to inform recipients that You have modified the Original Work. + +7) *Warranty of Provenance and Disclaimer of Warranty.* Licensor +warrants that the copyright in and to the Original Work and the patent +rights granted herein by Licensor are owned by the Licensor or are +sublicensed to You under the terms of this License with the permission +of the contributor(s) of those copyrights and patent rights. Except as +expressly stated in the immediately proceeding sentence, the Original +Work is provided under this License on an "AS IS" BASIS and WITHOUT +WARRANTY, either express or implied, including, without limitation, the +warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL +WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential +part of this License. No license to Original Work is granted hereunder +except under this disclaimer. + +8) *Limitation of Liability.* Under no circumstances and under no legal +theory, whether in tort (including negligence), contract, or otherwise, +shall the Licensor be liable to any person for any direct, indirect, +special, incidental, or consequential damages of any character arising +as a result of this License or the use of the Original Work including, +without limitation, damages for loss of goodwill, work stoppage, +computer failure or malfunction, or any and all other commercial damages +or losses. This limitation of liability shall not apply to liability for +death or personal injury resulting from Licensor's negligence to the +extent applicable law prohibits such limitation. Some jurisdictions do +not allow the exclusion or limitation of incidental or consequential +damages, so this exclusion and limitation may not apply to You. + +9) *Acceptance and Termination.* If You distribute copies of the +Original Work or a Derivative Work, You must make a reasonable effort +under the circumstances to obtain the express assent of recipients to +the terms of this License. Nothing else but this License (or another +written agreement between Licensor and You) grants You permission to +create Derivative Works based upon the Original Work or to exercise any +of the rights granted in Section 1 herein, and any attempt to do so +except under the terms of this License (or another written agreement +between Licensor and You) is expressly prohibited by U.S. copyright law, +the equivalent laws of other countries, and by international treaty. +Therefore, by exercising any of the rights granted to You in Section 1 +herein, You indicate Your acceptance of this License and all of its +terms and conditions. + +10) *Termination for Patent Action.* This License shall terminate +automatically and You may no longer exercise any of the rights granted +to You by this License as of the date You commence an action, including +a cross-claim or counterclaim, for patent infringement (i) against +Licensor with respect to a patent applicable to software or (ii) against +any entity with respect to a patent applicable to the Original Work (but +excluding combinations of the Original Work with other software or +hardware). + +11) *Jurisdiction, Venue and Governing Law.* Any action or suit relating +to this License may be brought only in the courts of a jurisdiction +wherein the Licensor resides or in which Licensor conducts its primary +business, and under the laws of that jurisdiction excluding its +conflict-of-law provisions. The application of the United Nations +Convention on Contracts for the International Sale of Goods is expressly +excluded. Any use of the Original Work outside the scope of this License +or after its termination shall be subject to the requirements and +penalties of the U.S. Copyright Act, 17 U.S.C. - 101 et seq., the +equivalent laws of other countries, and international treaty. This +section shall survive the termination of this License. + +12) *Attorneys Fees.* In any action to enforce the terms of this License +or seeking damages relating thereto, the prevailing party shall be +entitled to recover its costs and expenses, including, without +limitation, reasonable attorneys' fees and costs incurred in connection +with such action, including any appeal of such action. This section +shall survive the termination of this License. + +13) *Miscellaneous.* This License represents the complete agreement +concerning the subject matter hereof. If any provision of this License +is held to be unenforceable, such provision shall be reformed only to +the extent necessary to make it enforceable. + +14) *Definition of "You" in This License.* "You" throughout this +License, whether in upper or lower case, means an individual or a legal +entity exercising rights under, and complying with all of the terms of, +this License. For legal entities, "You" includes any entity that +controls, is controlled by, or is under common control with you. For +purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or +more of the outstanding shares, or (iii) beneficial ownership of such +entity. + +15) *Right to Use.* You may use the Original Work in all ways not +otherwise restricted or conditioned by this License or by law, and +Licensor promises not to interfere with or be responsible for such uses +by You. + +This license is Copyright (C) 2003 Lawrence E. Rosen. All rights +reserved. Permission is hereby granted to copy and distribute this +license without modification. This license may not be modified without +the express written permission of its copyright owner. + diff --git a/src/libSystem/makefile b/src/libSystem/makefile index 272fb2f..3ee835c 100644 --- a/src/libSystem/makefile +++ b/src/libSystem/makefile @@ -26,7 +26,7 @@ LD_FLAGS = $(CLINK) $(ALIGN) $(SHARED) $(ENTRYPOINT) $(STRIP) LD_DIRS = -L$(PREFIX)/i386-pc-xbox/lib -L$(PREFIX)/lib LD_LIBS = $(LD_DIRS) -lmscorlib -lm -lopenxdk -lhal -lc -lusb -lc -lxboxkrnl -lc -lhal -lxboxkrnl -lhal -lopenxdk -lc -lgcc -lstdc++ -OBJS = CancelEventArgs.o Debug.o DnsEndPoint.o EndPoint.o IPAddress.o IPEndPoint.o NetworkChange.o NetworkInterface.o Socket.o SocketAddress.o SocketAsyncEventArgs.o Stopwatch.o +OBJS = CancelEventArgs.o Debug.o DnsEndPoint.o EndPoint.o IPAddress.o IPEndPoint.o NetworkChange.o NetworkInterface.o pktdrv.o Socket.o SocketAddress.o SocketAsyncEventArgs.o Stopwatch.o all: libSystem.a diff --git a/src/libSystem/pktdrv.c b/src/libSystem/pktdrv.c new file mode 100644 index 0000000..ac76635 --- /dev/null +++ b/src/libSystem/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/libSystem/pktdrv.h b/src/libSystem/pktdrv.h new file mode 100644 index 0000000..888527c --- /dev/null +++ b/src/libSystem/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