12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- raw.c
- Abstract:
- This module implements the raw socket protocol.
- Author:
- Chris Stevens 20-May-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Protocol drivers are supposed to be able to stand on their own (ie be able to
- // be implemented outside the core net library). For the builtin ones, avoid
- // including netcore.h, but still redefine those functions that would otherwise
- // generate imports.
- //
- #define NET_API __DLLEXPORT
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the allocation tag used by the raw socket protocol.
- //
- #define RAW_PROTOCOL_ALLOCATION_TAG 0x21707352 // '!psR'
- //
- // Define the default size of the RAW socket's receive data buffer, in bytes.
- //
- #define RAW_DEFAULT_RECEIVE_BUFFER_SIZE (256 * _1KB)
- //
- // Define the minimum receive buffer size.
- //
- #define RAW_MIN_RECEIVE_BUFFER_SIZE _2KB
- //
- // Define the default minimum number of bytes necessary for the RAW socket to
- // become readable.
- //
- #define RAW_DEFAULT_RECEIVE_MINIMUM 1
- //
- // Define the minimum number of bytes necessary for RAW sockets to become
- // writable. There is no minimum and bytes are immediately sent on the wire.
- //
- #define RAW_SEND_MINIMUM 1
- //
- // Define the maximum packet size allowed on a raw socket.
- //
- #define RAW_MAX_PACKET_SIZE MAX_ULONG
- //
- // Define the default protocol entry flags.
- //
- #define RAW_DEFAULT_PROTOCOL_FLAGS \
- NET_PROTOCOL_FLAG_MATCH_ANY_PROTOCOL | \
- NET_PROTOCOL_FLAG_FIND_ALL_SOCKETS | \
- NET_PROTOCOL_FLAG_NO_DEFAULT_PROTOCOL | \
- NET_PROTOCOL_FLAG_PORTLESS | \
- NET_PROTOCOL_FLAG_NO_BIND_PERMISSIONS
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines a raw socket protocol's data socket.
- Members:
- NetSocket - Stores the common core networking parameters.
- ReceivedPacketList - Stores the list of packets ready to be read by the
- user.
- ReceiveLock - Stores the lock that protects the received packets list,
- dropped packet count, and various receive buffer parameters. This lock
- must always be acquired at low level.
- ReceiveBufferTotalSize - Stores the total size of the receive buffer, in
- bytes. Packets that are received but will not fit in the buffer are
- discarded.
- ReceiveBufferFreeSize - Stores the receive buffer's free space, in bytes.
- Packets that are received but do not fit in the free space are
- discarded.
- ReceiveTimeout - Stores the maximum amount of time, in milliseconds, that
- the socket will wait when receiving data.
- ReceiveMinimum - Stores the minimum amount of bytes that must be available
- before the socket is made readable. This is ignored.
- DroppedPacketCount - Stores the number of packets that have been dropped
- because the receive queue was full.
- ShutdownTypes - Stores the mask of shutdowns that have occurred on this
- socket.
- MaxPacketSize - Stores the maximum size of RAW datagrams.
- --*/
- typedef struct _RAW_SOCKET {
- NET_SOCKET NetSocket;
- LIST_ENTRY ReceivedPacketList;
- PQUEUED_LOCK ReceiveLock;
- ULONG ReceiveBufferTotalSize;
- ULONG ReceiveBufferFreeSize;
- ULONG ReceiveTimeout;
- ULONG ReceiveMinimum;
- ULONG DroppedPacketCount;
- ULONG MaxPacketSize;
- ULONG ShutdownTypes;
- } RAW_SOCKET, *PRAW_SOCKET;
- /*++
- Structure Description:
- This structure defines a raw socket protocol received message.
- Members:
- ListEntry - Stores pointers to the next and previous packets.
- Address - Stores the network address where this data came from.
- DataBuffer - Stores a pointer to the buffer containing the actual data.
- Size - Stores the number of bytes in the data buffer.
- --*/
- typedef struct _RAW_RECEIVED_PACKET {
- LIST_ENTRY ListEntry;
- NETWORK_ADDRESS Address;
- PVOID DataBuffer;
- ULONG Size;
- } RAW_RECEIVED_PACKET, *PRAW_RECEIVED_PACKET;
- /*++
- Structure Description:
- This structure defines a raw socket option.
- Members:
- InformationType - Stores the information type for the socket option.
- Option - Stores the type-specific option identifier.
- Size - Stores the size of the option value, in bytes.
- SetAllowed - Stores a boolean indicating whether or not the option is
- allowed to be set.
- --*/
- typedef struct _RAW_SOCKET_OPTION {
- SOCKET_INFORMATION_TYPE InformationType;
- UINTN Option;
- UINTN Size;
- BOOL SetAllowed;
- } RAW_SOCKET_OPTION, *PRAW_SOCKET_OPTION;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- NetpRawCreateSocket (
- PNET_PROTOCOL_ENTRY ProtocolEntry,
- PNET_NETWORK_ENTRY NetworkEntry,
- ULONG NetworkProtocol,
- PNET_SOCKET *NewSocket,
- ULONG Phase
- );
- VOID
- NetpRawDestroySocket (
- PNET_SOCKET Socket
- );
- KSTATUS
- NetpRawBindToAddress (
- PNET_SOCKET Socket,
- PNET_LINK Link,
- PNETWORK_ADDRESS Address
- );
- KSTATUS
- NetpRawListen (
- PNET_SOCKET Socket
- );
- KSTATUS
- NetpRawAccept (
- PNET_SOCKET Socket,
- PIO_HANDLE *NewConnectionSocket,
- PNETWORK_ADDRESS RemoteAddress
- );
- KSTATUS
- NetpRawConnect (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS Address
- );
- KSTATUS
- NetpRawClose (
- PNET_SOCKET Socket
- );
- KSTATUS
- NetpRawShutdown (
- PNET_SOCKET Socket,
- ULONG ShutdownType
- );
- KSTATUS
- NetpRawSend (
- BOOL FromKernelMode,
- PNET_SOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- );
- VOID
- NetpRawProcessReceivedData (
- PNET_RECEIVE_CONTEXT ReceiveContext
- );
- KSTATUS
- NetpRawProcessReceivedSocketData (
- PNET_SOCKET Socket,
- PNET_RECEIVE_CONTEXT ReceiveContext
- );
- KSTATUS
- NetpRawReceive (
- BOOL FromKernelMode,
- PNET_SOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- );
- KSTATUS
- NetpRawGetSetInformation (
- PNET_SOCKET Socket,
- SOCKET_INFORMATION_TYPE InformationType,
- UINTN SocketOption,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- );
- KSTATUS
- NetpRawUserControl (
- PNET_SOCKET Socket,
- ULONG CodeNumber,
- BOOL FromKernelMode,
- PVOID ContextBuffer,
- UINTN ContextBufferSize
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- NET_PROTOCOL_ENTRY NetRawProtocol = {
- {NULL, NULL},
- NetSocketRaw,
- SOCKET_INTERNET_PROTOCOL_RAW,
- RAW_DEFAULT_PROTOCOL_FLAGS,
- NULL,
- NULL,
- {{0}, {0}, {0}},
- {
- NetpRawCreateSocket,
- NetpRawDestroySocket,
- NetpRawBindToAddress,
- NetpRawListen,
- NetpRawAccept,
- NetpRawConnect,
- NetpRawClose,
- NetpRawShutdown,
- NetpRawSend,
- NetpRawProcessReceivedData,
- NetpRawProcessReceivedSocketData,
- NetpRawReceive,
- NetpRawGetSetInformation,
- NetpRawUserControl
- }
- };
- RAW_SOCKET_OPTION NetRawSocketOptions[] = {
- {
- SocketInformationBasic,
- SocketBasicOptionSendBufferSize,
- sizeof(ULONG),
- TRUE
- },
- {
- SocketInformationBasic,
- SocketBasicOptionSendMinimum,
- sizeof(ULONG),
- FALSE
- },
- {
- SocketInformationBasic,
- SocketBasicOptionReceiveBufferSize,
- sizeof(ULONG),
- TRUE
- },
- {
- SocketInformationBasic,
- SocketBasicOptionReceiveMinimum,
- sizeof(ULONG),
- TRUE
- },
- {
- SocketInformationBasic,
- SocketBasicOptionReceiveTimeout,
- sizeof(SOCKET_TIME),
- TRUE
- },
- };
- //
- // Store the number of raw sockets that could potentially receive a packet.
- //
- volatile UINTN NetRawSocketCount = 0;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- NetpRawInitialize (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes support for raw sockets.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- //
- // Register the raw socket handler with the core networking library. There
- // is no real "raw protocol", so this is a special protocol that gets to
- // filter packets from every protocol.
- //
- Status = NetRegisterProtocol(&NetRawProtocol, NULL);
- if (!KSUCCESS(Status)) {
- ASSERT(FALSE);
- }
- return;
- }
- KSTATUS
- NetpRawCreateSocket (
- PNET_PROTOCOL_ENTRY ProtocolEntry,
- PNET_NETWORK_ENTRY NetworkEntry,
- ULONG NetworkProtocol,
- PNET_SOCKET *NewSocket,
- ULONG Phase
- )
- /*++
- Routine Description:
- This routine allocates resources associated with a new socket. The protocol
- driver is responsible for allocating the structure (with additional length
- for any of its context). The core networking library will fill in the
- common header when this routine returns.
- Arguments:
- ProtocolEntry - Supplies a pointer to the protocol information.
- NetworkEntry - Supplies a pointer to the network information.
- NetworkProtocol - Supplies the raw protocol value for this socket used on
- the network. This value is network specific.
- NewSocket - Supplies a pointer where a pointer to a newly allocated
- socket structure will be returned. The caller is responsible for
- allocating the socket (and potentially a larger structure for its own
- context). The core network library will fill in the standard socket
- structure after this routine returns. In phase 1, this will contain
- a pointer to the socket allocated during phase 0.
- Phase - Supplies the socket creation phase. Phase 0 is the allocation phase
- and phase 1 is the advanced initialization phase, which is invoked
- after net core is done filling out common portions of the socket
- structure.
- Return Value:
- Status code.
- --*/
- {
- NETWORK_ADDRESS LocalAddress;
- PNET_SOCKET NetSocket;
- PNET_PACKET_SIZE_INFORMATION PacketSizeInformation;
- PRAW_SOCKET RawSocket;
- KSTATUS Status;
- ASSERT(ProtocolEntry->Type == NetSocketRaw);
- ASSERT(ProtocolEntry->ParentProtocolNumber == SOCKET_INTERNET_PROTOCOL_RAW);
- NetSocket = NULL;
- RawSocket = NULL;
- //
- // The thread must have permission to create raw sockets.
- //
- Status = PsCheckPermission(PERMISSION_NET_RAW);
- if (!KSUCCESS(Status)) {
- goto RawCreateSocketEnd;
- }
- //
- // Phase 0 allocates the socket and begins initialization.
- //
- if (Phase == 0) {
- RawSocket = MmAllocatePagedPool(sizeof(RAW_SOCKET),
- RAW_PROTOCOL_ALLOCATION_TAG);
- if (RawSocket == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto RawCreateSocketEnd;
- }
- RtlZeroMemory(RawSocket, sizeof(RAW_SOCKET));
- NetSocket = &(RawSocket->NetSocket);
- NetSocket->KernelSocket.Protocol = NetworkProtocol;
- NetSocket->KernelSocket.ReferenceCount = 1;
- INITIALIZE_LIST_HEAD(&(RawSocket->ReceivedPacketList));
- RawSocket->ReceiveTimeout = WAIT_TIME_INDEFINITE;
- RawSocket->ReceiveBufferTotalSize = RAW_DEFAULT_RECEIVE_BUFFER_SIZE;
- RawSocket->ReceiveBufferFreeSize = RawSocket->ReceiveBufferTotalSize;
- RawSocket->ReceiveMinimum = RAW_DEFAULT_RECEIVE_MINIMUM;
- RawSocket->MaxPacketSize = RAW_MAX_PACKET_SIZE;
- RawSocket->ReceiveLock = KeCreateQueuedLock();
- if (RawSocket->ReceiveLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto RawCreateSocketEnd;
- }
- //
- // Set some kernel socket fields. A raw socket needs to be bound to the
- // any address and made ready to receive as soon as create returns. To
- // avoid requiring common code to handle this, initialize the kernel
- // socket so that the bind routines can be invoked.
- //
- NetSocket->KernelSocket.IoState = IoCreateIoObjectState(FALSE, FALSE);
- if (NetSocket->KernelSocket.IoState == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto RawCreateSocketEnd;
- }
- NetSocket->KernelSocket.Domain = NetworkEntry->Domain;
- NetSocket->KernelSocket.Type = ProtocolEntry->Type;
- //
- // Give the lower layers a chance to initialize. Start the maximum
- // packet size at the largest possible value.
- //
- ASSERT(RAW_MAX_PACKET_SIZE == MAX_ULONG);
- PacketSizeInformation = &(NetSocket->PacketSizeInformation);
- PacketSizeInformation->MaxPacketSize = RAW_MAX_PACKET_SIZE;
- Status = NetworkEntry->Interface.InitializeSocket(ProtocolEntry,
- NetworkEntry,
- NetworkProtocol,
- NetSocket);
- if (!KSUCCESS(Status)) {
- goto RawCreateSocketEnd;
- }
- RtlAtomicAdd(&NetRawSocketCount, 1);
- Status = STATUS_SUCCESS;
- //
- // Phase 1 finishes raw specific initialization after netcore is done with
- // its initialization steps.
- //
- } else {
- ASSERT(Phase == 1);
- ASSERT(*NewSocket != NULL);
- ASSERT(RawSocket == NULL);
- NetSocket = *NewSocket;
- //
- // Perform the implicit bind to the any address.
- //
- RtlZeroMemory(&LocalAddress, sizeof(NETWORK_ADDRESS));
- LocalAddress.Domain = NetSocket->KernelSocket.Domain;
- Status = NetpRawBindToAddress(NetSocket, NULL, &LocalAddress);
- if (!KSUCCESS(Status)) {
- goto RawCreateSocketEnd;
- }
- }
- RawCreateSocketEnd:
- if (!KSUCCESS(Status)) {
- if (RawSocket != NULL) {
- if (RawSocket->ReceiveLock != NULL) {
- KeDestroyQueuedLock(RawSocket->ReceiveLock);
- }
- MmFreePagedPool(RawSocket);
- RawSocket = NULL;
- NetSocket = NULL;
- }
- }
- *NewSocket = NetSocket;
- return Status;
- }
- VOID
- NetpRawDestroySocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine destroys resources associated with an open socket, officially
- marking the end of the kernel and core networking library's knowledge of
- this structure.
- Arguments:
- Socket - Supplies a pointer to the socket to destroy. The core networking
- library will have already destroyed any resources inside the common
- header, the protocol should not reach through any pointers inside the
- socket header except the protocol and network entries.
- Return Value:
- None. This routine is responsible for freeing the memory associated with
- the socket structure itself.
- --*/
- {
- PRAW_RECEIVED_PACKET Packet;
- PRAW_SOCKET RawSocket;
- RawSocket = (PRAW_SOCKET)Socket;
- //
- // Loop through and free any leftover packets.
- //
- KeAcquireQueuedLock(RawSocket->ReceiveLock);
- while (!LIST_EMPTY(&(RawSocket->ReceivedPacketList))) {
- Packet = LIST_VALUE(RawSocket->ReceivedPacketList.Next,
- RAW_RECEIVED_PACKET,
- ListEntry);
- LIST_REMOVE(&(Packet->ListEntry));
- RawSocket->ReceiveBufferFreeSize += Packet->Size;
- MmFreePagedPool(Packet);
- }
- ASSERT(RawSocket->ReceiveBufferFreeSize ==
- RawSocket->ReceiveBufferTotalSize);
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- if (Socket->Network->Interface.DestroySocket != NULL) {
- Socket->Network->Interface.DestroySocket(Socket);
- }
- KeDestroyQueuedLock(RawSocket->ReceiveLock);
- MmFreePagedPool(RawSocket);
- RtlAtomicAdd(&NetRawSocketCount, (UINTN)-1);
- return;
- }
- KSTATUS
- NetpRawBindToAddress (
- PNET_SOCKET Socket,
- PNET_LINK Link,
- PNETWORK_ADDRESS Address
- )
- /*++
- Routine Description:
- This routine binds the given socket to the specified network address.
- Usually this is a no-op for the protocol, it's simply responsible for
- passing the request down to the network layer.
- Arguments:
- Socket - Supplies a pointer to the socket to bind.
- Link - Supplies an optional pointer to a link to bind to.
- Address - Supplies a pointer to the address to bind the socket to.
- Return Value:
- Status code.
- --*/
- {
- ULONG Flags;
- ULONG OriginalPort;
- KSTATUS Status;
- //
- // Allow raw sockets to get bound multiple times, unless they are already
- // connected to a peer address. They get bound to the any address upon
- // creation.
- //
- if (Socket->RemoteAddress.Domain != NetDomainInvalid) {
- Status = STATUS_INVALID_PARAMETER;
- goto RawBindToAddressEnd;
- }
- //
- // The port doesn't make a difference on raw sockets. Set it to the
- // protocol value, which is storked in the kernel socket.
- //
- OriginalPort = Address->Port;
- Address->Port = Socket->KernelSocket.Protocol;
- //
- // Pass the request down to the network layer. Raw sockets have slightly
- // different bind behavior than other socket types. Indicate this with the
- // flags.
- //
- Flags = NET_SOCKET_BINDING_FLAG_ALLOW_REBIND |
- NET_SOCKET_BINDING_FLAG_ALLOW_UNBIND |
- NET_SOCKET_BINDING_FLAG_NO_PORT_ASSIGNMENT |
- NET_SOCKET_BINDING_FLAG_OVERWRITE_LOCAL |
- NET_SOCKET_BINDING_FLAG_SKIP_ADDRESS_VALIDATION;
- Status = Socket->Network->Interface.BindToAddress(Socket,
- Link,
- Address,
- Flags);
- Address->Port = OriginalPort;
- if (!KSUCCESS(Status)) {
- goto RawBindToAddressEnd;
- }
- //
- // Begin listening immediately, as there is no explicit listen step for raw
- // sockets.
- //
- Status = Socket->Network->Interface.Listen(Socket);
- if (!KSUCCESS(Status)) {
- goto RawBindToAddressEnd;
- }
- IoSetIoObjectState(Socket->KernelSocket.IoState, POLL_EVENT_OUT, TRUE);
- RawBindToAddressEnd:
- return Status;
- }
- KSTATUS
- NetpRawListen (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine adds a bound socket to the list of listening sockets,
- officially allowing clients to attempt to connect to it.
- Arguments:
- Socket - Supplies a pointer to the socket to mark as listning.
- Return Value:
- Status code.
- --*/
- {
- return STATUS_NOT_SUPPORTED;
- }
- KSTATUS
- NetpRawAccept (
- PNET_SOCKET Socket,
- PIO_HANDLE *NewConnectionSocket,
- PNETWORK_ADDRESS RemoteAddress
- )
- /*++
- Routine Description:
- This routine accepts an incoming connection on a listening connection-based
- socket.
- Arguments:
- Socket - Supplies a pointer to the socket to accept a connection from.
- NewConnectionSocket - Supplies a pointer where a new socket will be
- returned that represents the accepted connection with the remote
- host.
- RemoteAddress - Supplies a pointer where the address of the connected
- remote host will be returned.
- Return Value:
- Status code.
- --*/
- {
- return STATUS_NOT_SUPPORTED;
- }
- KSTATUS
- NetpRawConnect (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS Address
- )
- /*++
- Routine Description:
- This routine attempts to make an outgoing connection to a server.
- Arguments:
- Socket - Supplies a pointer to the socket to use for the connection.
- Address - Supplies a pointer to the address to connect to.
- Return Value:
- Status code.
- --*/
- {
- ULONG OriginalPort;
- KSTATUS Status;
- //
- // Ports don't mean anything to raw sockets. Zero it out. Other
- // implementations seem to keep the port and return it for APIs like
- // getpeername(). This is confusing as a packet is never matched to a
- // socket based on the port. Setting it to zero also makes life easier when
- // searching for sockets during packet reception. The received packet has
- // no raw protocol port. If the socket were connected to some user defined
- // port, then the search compare routines would have to know to skip port
- // validation. Setting the port to zero allows the default compare routines
- // to be used.
- //
- OriginalPort = Address->Port;
- Address->Port = 0;
- //
- // Pass the request down to the network layer.
- //
- Status = Socket->Network->Interface.Connect(Socket, Address);
- Address->Port = OriginalPort;
- if (!KSUCCESS(Status)) {
- goto RawConnectEnd;
- }
- IoSetIoObjectState(Socket->KernelSocket.IoState, POLL_EVENT_OUT, TRUE);
- RawConnectEnd:
- return Status;
- }
- KSTATUS
- NetpRawClose (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine closes a socket connection.
- Arguments:
- Socket - Supplies a pointer to the socket to shut down.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // Close it at the lower level and then release the reference taken on
- // create if the close was successful.
- //
- Status = Socket->Network->Interface.Close(Socket);
- if (!KSUCCESS(Status)) {
- goto RawCloseEnd;
- }
- IoSocketReleaseReference(&(Socket->KernelSocket));
- RawCloseEnd:
- return Status;
- }
- KSTATUS
- NetpRawShutdown (
- PNET_SOCKET Socket,
- ULONG ShutdownType
- )
- /*++
- Routine Description:
- This routine shuts down communication with a given socket.
- Arguments:
- Socket - Supplies a pointer to the socket.
- ShutdownType - Supplies the shutdown type to perform. See the
- SOCKET_SHUTDOWN_* definitions.
- Return Value:
- Status code.
- --*/
- {
- PRAW_SOCKET RawSocket;
- //
- // Shutdown is not supported unless the socket is connected.
- //
- if (Socket->RemoteAddress.Domain == NetDomainInvalid) {
- return STATUS_NOT_CONNECTED;
- }
- RawSocket = (PRAW_SOCKET)Socket;
- RtlAtomicOr32(&(RawSocket->ShutdownTypes), ShutdownType);
- //
- // Signal the read event if the read end was shut down.
- //
- if ((ShutdownType & SOCKET_SHUTDOWN_READ) != 0) {
- KeAcquireQueuedLock(RawSocket->ReceiveLock);
- IoSetIoObjectState(Socket->KernelSocket.IoState, POLL_EVENT_IN, TRUE);
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- }
- if ((ShutdownType & SOCKET_SHUTDOWN_WRITE) != 0) {
- IoSetIoObjectState(Socket->KernelSocket.IoState, POLL_EVENT_OUT, TRUE);
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- NetpRawSend (
- BOOL FromKernelMode,
- PNET_SOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- )
- /*++
- Routine Description:
- This routine sends the given data buffer through the network using a
- specific protocol.
- Arguments:
- FromKernelMode - Supplies a boolean indicating whether the request is
- coming from kernel mode (TRUE) or user mode (FALSE).
- Socket - Supplies a pointer to the socket to send the data to.
- Parameters - Supplies a pointer to the socket I/O parameters. This will
- always be a kernel mode pointer.
- IoBuffer - Supplies a pointer to the I/O buffer containing the data to
- send.
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesComplete;
- PNETWORK_ADDRESS Destination;
- NETWORK_ADDRESS DestinationLocal;
- ULONG Flags;
- ULONG FooterSize;
- ULONG HeaderSize;
- PNET_LINK Link;
- NET_LINK_LOCAL_ADDRESS LinkInformation;
- PNET_SOCKET_LINK_OVERRIDE LinkOverride;
- NET_SOCKET_LINK_OVERRIDE LinkOverrideBuffer;
- PNET_PACKET_BUFFER Packet;
- NET_PACKET_LIST PacketList;
- PRAW_SOCKET RawSocket;
- UINTN Size;
- KSTATUS Status;
- BytesComplete = 0;
- Flags = Parameters->SocketIoFlags;
- Parameters->SocketIoFlags = 0;
- Link = NULL;
- LinkInformation.Link = NULL;
- LinkOverride = NULL;
- NET_INITIALIZE_PACKET_LIST(&PacketList);
- Size = Parameters->Size;
- RawSocket = (PRAW_SOCKET)Socket;
- Destination = Parameters->NetworkAddress;
- if ((Destination != NULL) && (FromKernelMode == FALSE)) {
- Status = MmCopyFromUserMode(&DestinationLocal,
- Destination,
- sizeof(NETWORK_ADDRESS));
- Destination = &DestinationLocal;
- if (!KSUCCESS(Status)) {
- goto RawSendEnd;
- }
- }
- if ((Destination == NULL) ||
- (Destination->Domain == NetDomainInvalid)) {
- if (Socket->RemoteAddress.Port == 0) {
- Status = STATUS_NOT_CONFIGURED;
- goto RawSendEnd;
- }
- Destination = &(Socket->RemoteAddress);
- } else if (Destination->Domain != Socket->KernelSocket.Domain) {
- Status = STATUS_DOMAIN_NOT_SUPPORTED;
- goto RawSendEnd;
- }
- //
- // Fail if the socket has already been closed for writing.
- //
- if ((RawSocket->ShutdownTypes & SOCKET_SHUTDOWN_WRITE) != 0) {
- if ((Flags & SOCKET_IO_NO_SIGNAL) != 0) {
- Status = STATUS_BROKEN_PIPE_SILENT;
- } else {
- Status = STATUS_BROKEN_PIPE;
- }
- goto RawSendEnd;
- }
- //
- // Fail if the socket's link went down.
- //
- if ((Socket->KernelSocket.IoState->Events & POLL_EVENT_DISCONNECTED) != 0) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto RawSendEnd;
- }
- //
- // Fail if there's ancillary data.
- //
- if (Parameters->ControlDataSize != 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto RawSendEnd;
- }
- //
- // If the socket has no link, then try to find a link that can service the
- // destination address.
- //
- if (Socket->Link == NULL) {
- Status = NetFindLinkForRemoteAddress(Destination, &LinkInformation);
- if (!KSUCCESS(Status)) {
- goto RawSendEnd;
- }
- //
- // Synchronously get the correct header, footer, and max packet sizes.
- //
- LinkOverride = &LinkOverrideBuffer;
- NetInitializeSocketLinkOverride(Socket, &LinkInformation, LinkOverride);
- }
- //
- // Set the necessary local variables based on whether the socket's link or
- // an override link will be used to send the data.
- //
- if (LinkOverride != NULL) {
- ASSERT(LinkOverride == &LinkOverrideBuffer);
- Link = LinkOverrideBuffer.LinkInformation.Link;
- HeaderSize = LinkOverrideBuffer.PacketSizeInformation.HeaderSize;
- FooterSize = LinkOverrideBuffer.PacketSizeInformation.FooterSize;
- } else {
- ASSERT(Socket->Link != NULL);
- Link = Socket->Link;
- HeaderSize = Socket->PacketSizeInformation.HeaderSize;
- FooterSize = Socket->PacketSizeInformation.FooterSize;
- }
- //
- // Allocate a buffer for the packet.
- //
- Status = NetAllocateBuffer(HeaderSize,
- Size,
- FooterSize,
- Link,
- 0,
- &Packet);
- if (!KSUCCESS(Status)) {
- goto RawSendEnd;
- }
- NET_ADD_PACKET_TO_LIST(Packet, &PacketList);
- //
- // Copy the packet data.
- //
- Status = MmCopyIoBufferData(IoBuffer,
- Packet->Buffer + Packet->DataOffset,
- BytesComplete,
- Size - BytesComplete,
- FALSE);
- if (!KSUCCESS(Status)) {
- goto RawSendEnd;
- }
- //
- // Send the datagram down to the network layer, which may have to send it
- // in fragments.
- //
- Status = Socket->Network->Interface.Send(Socket,
- Destination,
- LinkOverride,
- &PacketList);
- if (!KSUCCESS(Status)) {
- goto RawSendEnd;
- }
- Packet = NULL;
- BytesComplete = Size;
- RawSendEnd:
- Parameters->BytesCompleted = BytesComplete;
- if (!KSUCCESS(Status)) {
- NetDestroyBufferList(&PacketList);
- }
- if (LinkInformation.Link != NULL) {
- NetLinkReleaseReference(LinkInformation.Link);
- }
- if (LinkOverride == &(LinkOverrideBuffer)) {
- ASSERT(LinkOverrideBuffer.LinkInformation.Link != NULL);
- NetLinkReleaseReference(LinkOverrideBuffer.LinkInformation.Link);
- }
- return Status;
- }
- VOID
- NetpRawProcessReceivedData (
- PNET_RECEIVE_CONTEXT ReceiveContext
- )
- /*++
- Routine Description:
- This routine is called to process a received packet.
- Arguments:
- ReceiveContext - Supplies a pointer to the receive context that stores the
- link, packet, network, protocol, and source and destination addresses.
- Return Value:
- None. When the function returns, the memory associated with the packet may
- be reclaimed and reused.
- --*/
- {
- PNET_SOCKET PreviousSocket;
- PNET_SOCKET Socket;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // If no raw sockets are present, then immediately exit.
- //
- if (NetRawSocketCount == 0) {
- return;
- }
- //
- // Each raw sockets' local receive address was initialized with the port
- // set to the protocol number. Each raw socket's remote address was set to
- // 0 when it was fully bound. Initialize the receive context in this way
- // as well so that the ports will match any activated sockets.
- //
- ReceiveContext->Source->Port = 0;
- ReceiveContext->Destination->Port = ReceiveContext->ParentProtocolNumber;;
- //
- // Find all the sockets willing to take this packet.
- //
- Socket = NULL;
- PreviousSocket = NULL;
- do {
- Status = NetFindSocket(ReceiveContext, &Socket);
- if (!KSUCCESS(Status) && (Status != STATUS_MORE_PROCESSING_REQUIRED)) {
- break;
- }
- //
- // Pass the packet onto the socket for copying and safe keeping until
- // the data is read.
- //
- NetpRawProcessReceivedSocketData(Socket, ReceiveContext);
- //
- // Release the reference on the previous socket added by the find
- // socket call.
- //
- if (PreviousSocket != NULL) {
- IoSocketReleaseReference(&(PreviousSocket->KernelSocket));
- }
- PreviousSocket = Socket;
- } while (Status == STATUS_MORE_PROCESSING_REQUIRED);
- if (PreviousSocket != NULL) {
- IoSocketReleaseReference(&(PreviousSocket->KernelSocket));
- }
- ReceiveContext->Destination->Port = 0;
- return;
- }
- KSTATUS
- NetpRawProcessReceivedSocketData (
- PNET_SOCKET Socket,
- PNET_RECEIVE_CONTEXT ReceiveContext
- )
- /*++
- Routine Description:
- This routine is called for a particular socket to process a received packet
- that was sent to it.
- Arguments:
- Socket - Supplies a pointer to the socket that received the packet.
- ReceiveContext - Supplies a pointer to the receive context that stores the
- link, packet, network, protocol, and source and destination addresses.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- ULONG Length;
- PNET_PACKET_BUFFER Packet;
- PRAW_RECEIVED_PACKET RawPacket;
- PRAW_SOCKET RawSocket;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(Socket != NULL);
- RawSocket = (PRAW_SOCKET)Socket;
- Packet = ReceiveContext->Packet;
- Length = Packet->FooterOffset - Packet->DataOffset;
- //
- // Create a received packet entry for this data.
- //
- AllocationSize = sizeof(RAW_RECEIVED_PACKET) + Length;
- RawPacket = MmAllocatePagedPool(AllocationSize,
- RAW_PROTOCOL_ALLOCATION_TAG);
- if (RawPacket == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ProcessReceivedKernelDataEnd;
- }
- RtlCopyMemory(&(RawPacket->Address),
- ReceiveContext->Source,
- sizeof(NETWORK_ADDRESS));
- RawPacket->DataBuffer = (PVOID)(RawPacket + 1);
- RawPacket->Size = Length;
- //
- // Copy the packet contents into the receive packet buffer.
- //
- RtlCopyMemory(RawPacket->DataBuffer,
- Packet->Buffer + Packet->DataOffset,
- Length);
- //
- // Work to insert the packet on the list of received packets.
- //
- KeAcquireQueuedLock(RawSocket->ReceiveLock);
- if (RawPacket->Size <= RawSocket->ReceiveBufferFreeSize) {
- INSERT_BEFORE(&(RawPacket->ListEntry),
- &(RawSocket->ReceivedPacketList));
- RawSocket->ReceiveBufferFreeSize -= RawPacket->Size;
- ASSERT(RawSocket->ReceiveBufferFreeSize <
- RawSocket->ReceiveBufferTotalSize);
- //
- // One packet is always enough to notify a waiting receiver.
- //
- IoSetIoObjectState(Socket->KernelSocket.IoState, POLL_EVENT_IN, TRUE);
- RawPacket = NULL;
- } else {
- RawSocket->DroppedPacketCount += 1;
- }
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- //
- // If the packet wasn't nulled out, that's an indication it wasn't added to
- // the list, so free it up.
- //
- if (RawPacket != NULL) {
- MmFreePagedPool(RawPacket);
- }
- Status = STATUS_SUCCESS;
- ProcessReceivedKernelDataEnd:
- return Status;
- }
- KSTATUS
- NetpRawReceive (
- BOOL FromKernelMode,
- PNET_SOCKET Socket,
- PSOCKET_IO_PARAMETERS Parameters,
- PIO_BUFFER IoBuffer
- )
- /*++
- Routine Description:
- This routine is called by the user to receive data from the socket on a
- particular protocol.
- Arguments:
- FromKernelMode - Supplies a boolean indicating whether the request is
- coming from kernel mode (TRUE) or user mode (FALSE).
- Socket - Supplies a pointer to the socket to receive data from.
- Parameters - Supplies a pointer to the socket I/O parameters.
- IoBuffer - Supplies a pointer to the I/O buffer where the received data
- will be returned.
- Return Value:
- STATUS_SUCCESS if any bytes were read.
- STATUS_TIMEOUT if the request timed out.
- STATUS_BUFFER_TOO_SMALL if the incoming datagram was too large for the
- buffer. The remainder of the datagram is discarded in this case.
- Other error codes on other failures.
- --*/
- {
- UINTN BytesComplete;
- ULONG CopySize;
- ULONGLONG CurrentTime;
- ULONGLONG EndTime;
- ULONG Flags;
- BOOL LockHeld;
- PRAW_RECEIVED_PACKET Packet;
- PLIST_ENTRY PacketEntry;
- PRAW_SOCKET RawSocket;
- ULONG ReturnedEvents;
- ULONG ReturnSize;
- UINTN Size;
- KSTATUS Status;
- ULONGLONG TimeCounterFrequency;
- ULONG Timeout;
- ULONG WaitTime;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- BytesComplete = 0;
- EndTime = 0;
- LockHeld = FALSE;
- Flags = Parameters->SocketIoFlags;
- Parameters->SocketIoFlags = 0;
- Size = Parameters->Size;
- TimeCounterFrequency = 0;
- Timeout = Parameters->TimeoutInMilliseconds;
- RawSocket = (PRAW_SOCKET)Socket;
- if ((Flags & SOCKET_IO_OUT_OF_BAND) != 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto RawReceiveEnd;
- }
- //
- // Fail if there's ancillary data.
- //
- if (Parameters->ControlDataSize != 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto RawReceiveEnd;
- }
- //
- // Set a timeout timer to give up on. The socket stores the maximum timeout.
- //
- if (Timeout > RawSocket->ReceiveTimeout) {
- Timeout = RawSocket->ReceiveTimeout;
- }
- if ((Timeout != 0) && (Timeout != WAIT_TIME_INDEFINITE)) {
- EndTime = KeGetRecentTimeCounter();
- EndTime += KeConvertMicrosecondsToTimeTicks(
- Timeout * MICROSECONDS_PER_MILLISECOND);
- TimeCounterFrequency = HlQueryTimeCounterFrequency();
- }
- //
- // Loop trying to get some data. This loop exits once one packet is read.
- //
- while (TRUE) {
- //
- // Wait for a packet to become available. Start by computing the wait
- // time.
- //
- if (Timeout == 0) {
- WaitTime = 0;
- } else if (Timeout != WAIT_TIME_INDEFINITE) {
- CurrentTime = KeGetRecentTimeCounter();
- WaitTime = (EndTime - CurrentTime) * MILLISECONDS_PER_SECOND /
- TimeCounterFrequency;
- } else {
- WaitTime = WAIT_TIME_INDEFINITE;
- }
- //
- // Wait for something to maybe become available. If the wait fails due
- // to a timeout, interruption, or something else, then fail out.
- // Otherwise when the read event is signalled, there are at least one
- // packet available.
- //
- Status = IoWaitForIoObjectState(Socket->KernelSocket.IoState,
- POLL_EVENT_IN,
- TRUE,
- WaitTime,
- &ReturnedEvents);
- if (!KSUCCESS(Status)) {
- goto RawReceiveEnd;
- }
- if ((ReturnedEvents & POLL_ERROR_EVENTS) != 0) {
- if ((ReturnedEvents & POLL_EVENT_DISCONNECTED) != 0) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- } else {
- Status = NET_SOCKET_GET_LAST_ERROR(Socket);
- if (KSUCCESS(Status)) {
- Status = STATUS_DEVICE_IO_ERROR;
- }
- }
- goto RawReceiveEnd;
- }
- KeAcquireQueuedLock(RawSocket->ReceiveLock);
- LockHeld = TRUE;
- //
- // Fail with EOF if the socket has already been closed for reading.
- //
- if ((RawSocket->ShutdownTypes & SOCKET_SHUTDOWN_READ) != 0) {
- Status = STATUS_END_OF_FILE;
- goto RawReceiveEnd;
- }
- //
- // If another thread beat this one to the punch, try again.
- //
- if (LIST_EMPTY(&(RawSocket->ReceivedPacketList)) != FALSE) {
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- LockHeld = FALSE;
- continue;
- }
- //
- // This should be the first packet being read.
- //
- ASSERT(BytesComplete == 0);
- PacketEntry = RawSocket->ReceivedPacketList.Next;
- Packet = LIST_VALUE(PacketEntry, RAW_RECEIVED_PACKET, ListEntry);
- ReturnSize = Packet->Size;
- CopySize = ReturnSize;
- if (CopySize > Size) {
- Parameters->SocketIoFlags |= SOCKET_IO_DATA_TRUNCATED;
- CopySize = Size;
- //
- // The real packet size is only returned to the user on truncation
- // if the truncated flag was supplied to this routine. Default to
- // returning the truncated size.
- //
- if ((Flags & SOCKET_IO_DATA_TRUNCATED) == 0) {
- ReturnSize = CopySize;
- }
- }
- Status = MmCopyIoBufferData(IoBuffer,
- Packet->DataBuffer,
- 0,
- CopySize,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto RawReceiveEnd;
- }
- //
- // Copy the packet address out to the caller if requested.
- //
- if (Parameters->NetworkAddress != NULL) {
- if (FromKernelMode != FALSE) {
- RtlCopyMemory(Parameters->NetworkAddress,
- &(Packet->Address),
- sizeof(NETWORK_ADDRESS));
- } else {
- Status = MmCopyToUserMode(Parameters->NetworkAddress,
- &(Packet->Address),
- sizeof(NETWORK_ADDRESS));
- if (!KSUCCESS(Status)) {
- goto RawReceiveEnd;
- }
- }
- }
- BytesComplete = ReturnSize;
- //
- // Remove the packet if not peeking.
- //
- if ((Flags & SOCKET_IO_PEEK) == 0) {
- LIST_REMOVE(&(Packet->ListEntry));
- RawSocket->ReceiveBufferFreeSize += Packet->Size;
- //
- // The total receive buffer size may have been decreased. Don't
- // increment the free size above the total.
- //
- if (RawSocket->ReceiveBufferFreeSize >
- RawSocket->ReceiveBufferTotalSize) {
- RawSocket->ReceiveBufferFreeSize =
- RawSocket->ReceiveBufferTotalSize;
- }
- MmFreePagedPool(Packet);
- //
- // Unsignal the IN event if there are no more packets.
- //
- if (LIST_EMPTY(&(RawSocket->ReceivedPacketList)) != FALSE) {
- IoSetIoObjectState(Socket->KernelSocket.IoState,
- POLL_EVENT_IN,
- FALSE);
- }
- }
- //
- // Wait-all does not apply to raw sockets. Break out.
- //
- Status = STATUS_SUCCESS;
- break;
- }
- RawReceiveEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- }
- Parameters->BytesCompleted = BytesComplete;
- return Status;
- }
- KSTATUS
- NetpRawGetSetInformation (
- PNET_SOCKET Socket,
- SOCKET_INFORMATION_TYPE InformationType,
- UINTN Option,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets properties of the given socket.
- Arguments:
- Socket - Supplies a pointer to the socket to get or set information for.
- InformationType - Supplies the socket information type category to which
- specified option belongs.
- Option - Supplies the option to get or set, which is specific to the
- information type. The type of this value is generally
- SOCKET_<information_type>_OPTION.
- Data - Supplies a pointer to the data buffer where the data is either
- returned for a get operation or given for a set operation.
- DataSize - Supplies a pointer that on input constains the size of the data
- buffer. On output, this contains the required size of the data buffer.
- Set - Supplies a boolean indicating if this is a get operation (FALSE) or
- a set operation (TRUE).
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the information type is incorrect.
- STATUS_BUFFER_TOO_SMALL if the data buffer is too small to receive the
- requested option.
- STATUS_NOT_SUPPORTED_BY_PROTOCOL if the socket option is not supported by
- the socket.
- STATUS_NOT_HANDLED if the protocol does not override the default behavior
- for a basic socket option.
- --*/
- {
- ULONG Count;
- ULONG Index;
- LONGLONG Milliseconds;
- PRAW_SOCKET_OPTION RawOption;
- PRAW_SOCKET RawSocket;
- PNET_PACKET_SIZE_INFORMATION SizeInformation;
- ULONG SizeOption;
- PSOCKET_TIME SocketTime;
- SOCKET_TIME SocketTimeBuffer;
- PVOID Source;
- KSTATUS Status;
- RawSocket = (PRAW_SOCKET)Socket;
- if ((InformationType != SocketInformationBasic) &&
- (InformationType != SocketInformationUdp)) {
- Status = STATUS_NOT_SUPPORTED;
- goto RawGetSetInformationEnd;
- }
- //
- // Search to see if the socket option is supported by the raw protocol.
- //
- Count = sizeof(NetRawSocketOptions) / sizeof(NetRawSocketOptions[0]);
- for (Index = 0; Index < Count; Index += 1) {
- RawOption = &(NetRawSocketOptions[Index]);
- if ((RawOption->InformationType == InformationType) &&
- (RawOption->Option == Option)) {
- break;
- }
- }
- if (Index == Count) {
- if (InformationType == SocketInformationBasic) {
- Status = STATUS_NOT_HANDLED;
- } else {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- }
- goto RawGetSetInformationEnd;
- }
- //
- // Handle failure cases common to all options.
- //
- if (Set != FALSE) {
- if (RawOption->SetAllowed == FALSE) {
- Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
- goto RawGetSetInformationEnd;
- }
- if (*DataSize < RawOption->Size) {
- *DataSize = RawOption->Size;
- Status = STATUS_BUFFER_TOO_SMALL;
- goto RawGetSetInformationEnd;
- }
- }
- //
- // There are currently no raw protocol options.
- //
- ASSERT(InformationType != SocketInformationRaw);
- //
- // Parse the basic socket option, getting the information from the raw
- // socket or setting the new state in the raw socket.
- //
- Source = NULL;
- Status = STATUS_SUCCESS;
- switch ((SOCKET_BASIC_OPTION)Option) {
- case SocketBasicOptionSendBufferSize:
- if (Set != FALSE) {
- SizeOption = *((PULONG)Data);
- if (SizeOption > SOCKET_OPTION_MAX_ULONG) {
- SizeOption = SOCKET_OPTION_MAX_ULONG;
- }
- SizeInformation = &(Socket->PacketSizeInformation);
- if (SizeOption > RAW_MAX_PACKET_SIZE) {
- SizeOption = RAW_MAX_PACKET_SIZE;
- } else if (SizeOption < SizeInformation->MaxPacketSize) {
- SizeOption = SizeInformation->MaxPacketSize;
- }
- RawSocket->MaxPacketSize = SizeOption;
- } else {
- Source = &SizeOption;
- SizeOption = RawSocket->MaxPacketSize;
- }
- break;
- case SocketBasicOptionSendMinimum:
- ASSERT(Set == FALSE);
- Source = &SizeOption;
- SizeOption = RAW_SEND_MINIMUM;
- break;
- case SocketBasicOptionReceiveBufferSize:
- if (Set != FALSE) {
- SizeOption = *((PULONG)Data);
- if (SizeOption < RAW_MIN_RECEIVE_BUFFER_SIZE) {
- SizeOption = RAW_MIN_RECEIVE_BUFFER_SIZE;
- } else if (SizeOption > SOCKET_OPTION_MAX_ULONG) {
- SizeOption = SOCKET_OPTION_MAX_ULONG;
- }
- //
- // Set the receive buffer size and truncate the available free
- // space if necessary. Do not remove any packets that have already
- // been received. This is not meant to be a truncate call.
- //
- KeAcquireQueuedLock(RawSocket->ReceiveLock);
- RawSocket->ReceiveBufferTotalSize = SizeOption;
- if (RawSocket->ReceiveBufferFreeSize > SizeOption) {
- RawSocket->ReceiveBufferFreeSize = SizeOption;
- }
- KeReleaseQueuedLock(RawSocket->ReceiveLock);
- } else {
- Source = &SizeOption;
- SizeOption = RawSocket->ReceiveBufferTotalSize;
- }
- break;
- case SocketBasicOptionReceiveMinimum:
- if (Set != FALSE) {
- SizeOption = *((PULONG)Data);
- if (SizeOption > SOCKET_OPTION_MAX_ULONG) {
- SizeOption = SOCKET_OPTION_MAX_ULONG;
- }
- RawSocket->ReceiveMinimum = SizeOption;
- } else {
- Source = &SizeOption;
- SizeOption = RawSocket->ReceiveMinimum;
- }
- break;
- case SocketBasicOptionReceiveTimeout:
- if (Set != FALSE) {
- SocketTime = (PSOCKET_TIME)Data;
- if (SocketTime->Seconds < 0) {
- Status = STATUS_DOMAIN_ERROR;
- break;
- }
- Milliseconds = SocketTime->Seconds * MILLISECONDS_PER_SECOND;
- if (Milliseconds < SocketTime->Seconds) {
- Status = STATUS_DOMAIN_ERROR;
- break;
- }
- Milliseconds += SocketTime->Microseconds /
- MICROSECONDS_PER_MILLISECOND;
- if ((Milliseconds < 0) || (Milliseconds > MAX_LONG)) {
- Status = STATUS_DOMAIN_ERROR;
- break;
- }
- RawSocket->ReceiveTimeout = (ULONG)(LONG)Milliseconds;
- } else {
- Source = &SocketTimeBuffer;
- if (RawSocket->ReceiveTimeout == WAIT_TIME_INDEFINITE) {
- SocketTimeBuffer.Seconds = 0;
- SocketTimeBuffer.Microseconds = 0;
- } else {
- SocketTimeBuffer.Seconds = RawSocket->ReceiveTimeout /
- MILLISECONDS_PER_SECOND;
- SocketTimeBuffer.Microseconds = (RawSocket->ReceiveTimeout %
- MILLISECONDS_PER_SECOND) *
- MICROSECONDS_PER_MILLISECOND;
- }
- }
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- if (!KSUCCESS(Status)) {
- goto RawGetSetInformationEnd;
- }
- //
- // Truncate all copies for get requests down to the required size and only
- // return the required size on set requests.
- //
- if (*DataSize > RawOption->Size) {
- *DataSize = RawOption->Size;
- }
- //
- // For get requests, copy the gathered information to the supplied data
- // buffer.
- //
- if (Set == FALSE) {
- ASSERT(Source != NULL);
- RtlCopyMemory(Data, Source, *DataSize);
- //
- // If the copy truncated the data, report that the given buffer was too
- // small. The caller can choose to ignore this if the truncated data is
- // enough.
- //
- if (*DataSize < RawOption->Size) {
- *DataSize = RawOption->Size;
- Status = STATUS_BUFFER_TOO_SMALL;
- goto RawGetSetInformationEnd;
- }
- }
- RawGetSetInformationEnd:
- return Status;
- }
- KSTATUS
- NetpRawUserControl (
- PNET_SOCKET Socket,
- ULONG CodeNumber,
- BOOL FromKernelMode,
- PVOID ContextBuffer,
- UINTN ContextBufferSize
- )
- /*++
- Routine Description:
- This routine handles user control requests destined for a socket.
- Arguments:
- Socket - Supplies a pointer to the socket.
- CodeNumber - Supplies the minor code of the request.
- FromKernelMode - Supplies a boolean indicating whether or not this request
- (and the buffer associated with it) originates from user mode (FALSE)
- or kernel mode (TRUE).
- ContextBuffer - Supplies a pointer to the context buffer allocated by the
- caller for the request.
- ContextBufferSize - Supplies the size of the supplied context buffer.
- Return Value:
- Status code.
- --*/
- {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|