mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3528 lines
102 KiB
3528 lines
102 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
D:\nt\private\net\sockets\wshatm\wshatm.c
|
|
|
|
Abstract:
|
|
|
|
This module contains necessary routines for the ATM Windows Sockets
|
|
Helper DLL. This DLL provides the transport-specific support necessary
|
|
for the Windows Sockets DLL to use ATM as a transport.
|
|
|
|
Revision History:
|
|
|
|
arvindm 20-May-1997 Created based on TCP/IP's helper DLL, wshtcpip
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <wchar.h>
|
|
#include <tdi.h>
|
|
|
|
#include <winsock2.h>
|
|
#include <mswsock.h>
|
|
#include <ws2atm.h>
|
|
#include <wsahelp.h>
|
|
|
|
#include <tdistat.h>
|
|
#include <tdiinfo.h>
|
|
|
|
#include <rwanuser.h>
|
|
|
|
typedef unsigned long ulong;
|
|
typedef unsigned short ushort;
|
|
typedef unsigned int uint;
|
|
typedef unsigned char uchar;
|
|
#define TL_INSTANCE 0
|
|
|
|
#include <ws2atmsp.h>
|
|
|
|
#define NT // temporarily needed by tdiinfo.h...
|
|
|
|
#include <tdiinfo.h>
|
|
|
|
#include <basetyps.h>
|
|
#include <nspapi.h>
|
|
|
|
#define ATM_NAME L"ATM"
|
|
#define RWAN_NAME L"RawWan"
|
|
|
|
#define ATM_ADDR_SIZE 20
|
|
#define ATM_ADDR_BLANK_CHAR L' '
|
|
#define ATM_ADDR_PUNCTUATION_CHAR L'.'
|
|
#define ATM_ADDR_E164_START_CHAR '+'
|
|
|
|
#define ATM_AAL5_SOCK_TYPE SOCK_RAW
|
|
|
|
|
|
#define ATM_WSA_MULTIPOINT_FLAGS (WSA_FLAG_MULTIPOINT_C_ROOT | \
|
|
WSA_FLAG_MULTIPOINT_C_LEAF | \
|
|
WSA_FLAG_MULTIPOINT_D_ROOT | \
|
|
WSA_FLAG_MULTIPOINT_D_LEAF)
|
|
|
|
//
|
|
// Define valid flags for WSHOpenSocket2().
|
|
//
|
|
#define VALID_ATM_FLAGS (WSA_FLAG_OVERLAPPED | \
|
|
ATM_WSA_MULTIPOINT_FLAGS)
|
|
|
|
//
|
|
// Maximum expected size of ATM Connection Options: this includes the
|
|
// base QOS structure, plus all possible IEs.
|
|
//
|
|
#if 0
|
|
#define MAX_ATM_OPTIONS_LENGTH \
|
|
sizeof(QOS) + \
|
|
sizeof(Q2931_IE) + sizeof(AAL_PARAMETERS_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_TRAFFIC_DESCRIPTOR_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_BROADBAND_BEARER_CAPABILITY_IE) + \
|
|
(3 * (sizeof(Q2931_IE) + sizeof(ATM_BLLI_IE))) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_CALLED_PARTY_NUMBER_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_CALLED_PARTY_SUBADDRESS_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_CALLING_PARTY_SUBADDRESS_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_CAUSE_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_QOS_CLASS_IE) + \
|
|
sizeof(Q2931_IE) + sizeof(ATM_TRANSIT_NETWORK_SELECTION_IE)
|
|
|
|
#else
|
|
//
|
|
// Need much more with ATMUNI 4.0...
|
|
//
|
|
#define MAX_ATM_OPTIONS_LENGTH 1024
|
|
#endif
|
|
|
|
#if DBG1
|
|
#define DBGPRINT(stmt) { DbgPrint ("WSHATM: "); DbgPrint stmt; }
|
|
#else
|
|
#define DBGPRINT(stmt)
|
|
#endif // DBG1
|
|
|
|
#if DBG
|
|
extern
|
|
PVOID
|
|
MyRtlAllocateHeap(
|
|
IN PVOID HeapHandle,
|
|
IN ULONG Flags,
|
|
IN ULONG Size,
|
|
IN ULONG LineNumber
|
|
);
|
|
extern
|
|
VOID
|
|
MyRtlFreeHeap(
|
|
IN PVOID HeapHandle,
|
|
IN ULONG Flags,
|
|
IN PVOID MemPtr,
|
|
IN ULONG LineNumber
|
|
);
|
|
#define RTL_ALLOCATE_HEAP(_Handle, _Flags, _Size) MyRtlAllocateHeap(_Handle, _Flags, _Size, __LINE__)
|
|
#define RTL_FREE_HEAP(_Handle, _Flags, _Memptr) MyRtlFreeHeap(_Handle, _Flags, _Memptr, __LINE__)
|
|
#else
|
|
#define RTL_ALLOCATE_HEAP(_Handle, _Flags, _Size) RtlAllocateHeap(_Handle, _Flags, _Size)
|
|
#define RTL_FREE_HEAP(_Handle, _Flags, _Memptr) RtlFreeHeap(_Handle, _Flags, _Memptr)
|
|
#endif
|
|
|
|
#define ATM_AAL5_PACKET_SIZE 65535
|
|
|
|
//
|
|
// Structure and variables to define the triples supported by ATM. The
|
|
// first entry of each array is considered the canonical triple for
|
|
// that socket type; the other entries are synonyms for the first.
|
|
//
|
|
|
|
typedef struct _MAPPING_TRIPLE {
|
|
INT AddressFamily;
|
|
INT SocketType;
|
|
INT Protocol;
|
|
} MAPPING_TRIPLE, *PMAPPING_TRIPLE;
|
|
|
|
MAPPING_TRIPLE AtmMappingTriples[] = {
|
|
AF_ATM, ATM_AAL5_SOCK_TYPE, ATMPROTO_AAL5,
|
|
AF_ATM, ATM_AAL5_SOCK_TYPE, 0,
|
|
AF_ATM, SOCK_RAW, ATMPROTO_AAL5,
|
|
AF_ATM, SOCK_RAW, 0,
|
|
AF_ATM, 0, ATMPROTO_AAL5,
|
|
AF_UNSPEC, 0, ATMPROTO_AAL5,
|
|
AF_UNSPEC, ATM_AAL5_SOCK_TYPE, ATMPROTO_AAL5,
|
|
AF_UNSPEC, SOCK_RAW, ATMPROTO_AAL5
|
|
};
|
|
|
|
|
|
//
|
|
// Winsock 2 WSAPROTOCOL_INFO structures for all supported protocols.
|
|
//
|
|
|
|
#define ATM_UNI_VERSION 0x00030001 // For UNI 3.1
|
|
|
|
WSAPROTOCOL_INFOW Winsock2Protocols[] =
|
|
{
|
|
//
|
|
// ATM AAL5
|
|
//
|
|
|
|
{
|
|
XP1_GUARANTEED_ORDER // dwServiceFlags1
|
|
| XP1_MESSAGE_ORIENTED
|
|
// | XP1_PARTIAL_MESSAGE
|
|
| XP1_IFS_HANDLES
|
|
| XP1_SUPPORT_MULTIPOINT
|
|
| XP1_MULTIPOINT_DATA_PLANE
|
|
| XP1_MULTIPOINT_CONTROL_PLANE
|
|
| XP1_QOS_SUPPORTED,
|
|
0, // dwServiceFlags2
|
|
0, // dwServiceFlags3
|
|
0, // dwServiceFlags4
|
|
PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
|
|
{ // gProviderId
|
|
0, 0, 0,
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
},
|
|
0, // dwCatalogEntryId
|
|
{ // ProtocolChain
|
|
BASE_PROTOCOL, // ChainLen
|
|
{ 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
|
|
},
|
|
ATM_UNI_VERSION, // iVersion
|
|
AF_ATM, // iAddressFamily
|
|
sizeof(sockaddr_atm), // iMaxSockAddr
|
|
sizeof(sockaddr_atm), // iMinSockAddr
|
|
ATM_AAL5_SOCK_TYPE, // iSocketType
|
|
ATMPROTO_AAL5, // iProtocol
|
|
0, // iProtocolMaxOffset
|
|
BIGENDIAN, // iNetworkByteOrder
|
|
SECURITY_PROTOCOL_NONE, // iSecurityScheme
|
|
ATM_AAL5_PACKET_SIZE, // dwMessageSize
|
|
0, // dwProviderReserved
|
|
L"MSAFD ATM AAL5" // szProtocol
|
|
}
|
|
};
|
|
|
|
#define NUM_WINSOCK2_PROTOCOLS \
|
|
( sizeof(Winsock2Protocols) / sizeof(Winsock2Protocols[0]) )
|
|
|
|
//
|
|
// The GUID identifying this provider.
|
|
//
|
|
|
|
GUID AtmProviderGuid = { /* {C3656046-3AAF-11d1-A8C3-00C04FC99C9C} */
|
|
0xC3656046,
|
|
0x3AAF,
|
|
0x11D1,
|
|
{0xA8, 0xC3, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x9C}
|
|
};
|
|
|
|
//
|
|
// Given a digit (0-9) represented in ANSI, return its WCHAR representation
|
|
//
|
|
#define ANSI_TO_WCHAR(_AnsiDigit) \
|
|
(L'0' + (WCHAR)((_AnsiDigit) - '0'))
|
|
|
|
|
|
//
|
|
// Given a hex digit value (0-15), return its WCHAR representation
|
|
// (i.e. 0 -> L'0', 12 -> L'C')
|
|
//
|
|
#define DIGIT_TO_WCHAR(_Value) \
|
|
(((_Value) > 9)? (L'A' + (WCHAR)((_Value) - 10)) : \
|
|
(L'0' + (WCHAR)((_Value) - 0 )))
|
|
|
|
//
|
|
// The socket context structure for this DLL. Each open ATM socket
|
|
// will have one of these context structures, which is used to maintain
|
|
// information about the socket.
|
|
//
|
|
|
|
typedef struct _WSHATM_SOCKET_CONTEXT {
|
|
INT AddressFamily;
|
|
INT SocketType;
|
|
INT Protocol;
|
|
INT ReceiveBufferSize;
|
|
SOCKET SocketHandle;
|
|
DWORD Flags;
|
|
DWORD LocalFlags;
|
|
ATM_CONNECTION_ID ConnectionId;
|
|
|
|
} WSHATM_SOCKET_CONTEXT, *PWSHATM_SOCKET_CONTEXT;
|
|
|
|
#define DEFAULT_RECEIVE_BUFFER_SIZE ATM_AAL5_PACKET_SIZE
|
|
|
|
//
|
|
// LocalFlags in WSHATM_SOCKET_CONTEXT:
|
|
//
|
|
#define WSHATM_SOCK_IS_BOUND 0x00000001
|
|
#define WSHATM_SOCK_IS_PVC 0x00000004
|
|
#define WSHATM_SOCK_ASSOCIATE_PVC_PENDING 0x00000008
|
|
|
|
|
|
//
|
|
// Forward declarations of internal routines.
|
|
//
|
|
|
|
BOOLEAN
|
|
IsTripleInList (
|
|
IN PMAPPING_TRIPLE List,
|
|
IN ULONG ListLength,
|
|
IN INT AddressFamily,
|
|
IN INT SocketType,
|
|
IN INT Protocol
|
|
);
|
|
|
|
INT
|
|
WSHAtmSetQoS(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength
|
|
);
|
|
|
|
INT
|
|
WSHAtmGetQoS(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
);
|
|
|
|
INT
|
|
AtmQueryAtmGlobalInformation(
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN LPVOID pContext,
|
|
IN DWORD ContextLength,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
);
|
|
|
|
INT
|
|
AtmSetGenericObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN RWAN_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
INT
|
|
AtmGetGenericObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN RWAN_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
);
|
|
|
|
INT
|
|
AtmSetAtmObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
INT
|
|
AtmGetAtmObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
);
|
|
|
|
INT
|
|
AtmAssociatePVC(
|
|
IN SOCKET SocketHandle,
|
|
IN PVOID HelperDllSocketContext,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength
|
|
);
|
|
|
|
INT
|
|
AtmDoAssociatePVC(
|
|
IN PWSHATM_SOCKET_CONTEXT Context,
|
|
IN HANDLE TdiAddressObjectHandle
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
DllInitialize (
|
|
IN PVOID DllHandle,
|
|
IN ULONG Reason,
|
|
IN PVOID Context OPTIONAL
|
|
)
|
|
{
|
|
|
|
DBGPRINT(("DllInitialize, Reason %d\n", Reason));
|
|
|
|
switch ( Reason ) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
//
|
|
// We don't need to receive thread attach and detach
|
|
// notifications, so disable them to help application
|
|
// performance.
|
|
//
|
|
|
|
DisableThreadLibraryCalls( DllHandle );
|
|
|
|
return TRUE;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // SockInitialize
|
|
|
|
INT
|
|
WSHGetSockaddrType (
|
|
IN PSOCKADDR Sockaddr,
|
|
IN DWORD SockaddrLength,
|
|
OUT PSOCKADDR_INFO SockaddrInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses a sockaddr to determine the type of the
|
|
machine address and endpoint address portions of the sockaddr.
|
|
This is called by the winsock DLL whenever it needs to interpret
|
|
a sockaddr.
|
|
|
|
Arguments:
|
|
|
|
Sockaddr - a pointer to the sockaddr structure to evaluate.
|
|
|
|
SockaddrLength - the number of bytes in the sockaddr structure.
|
|
|
|
SockaddrInfo - a pointer to a structure that will receive information
|
|
about the specified sockaddr.
|
|
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNALIGNED SOCKADDR_ATM *sockaddr = (PSOCKADDR_ATM)Sockaddr;
|
|
ULONG i;
|
|
|
|
DBGPRINT(("GetSockaddrType: SockaddrLength %d, satm_family %d, AddrType x%x\n",
|
|
SockaddrLength, sockaddr->satm_family, sockaddr->satm_number.AddressType));
|
|
|
|
//
|
|
// Make sure that the address family is correct.
|
|
//
|
|
|
|
if ( sockaddr->satm_family != AF_ATM ) {
|
|
return WSAEAFNOSUPPORT;
|
|
}
|
|
|
|
//
|
|
// Make sure that the length is correct.
|
|
//
|
|
|
|
if ( SockaddrLength < sizeof(SOCKADDR_ATM) ) {
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// The ATM address part cannot be "absent".
|
|
//
|
|
if ( sockaddr->satm_number.AddressType == SAP_FIELD_ABSENT ) {
|
|
return WSAEINVAL;
|
|
}
|
|
#endif
|
|
|
|
if ( sockaddr->satm_number.NumofDigits > ATM_ADDR_SIZE ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// The address passed the tests, looks like a good address.
|
|
// Determine the type of the address and endpoint portions
|
|
// of the sockaddr.
|
|
//
|
|
|
|
if ( sockaddr->satm_number.AddressType == SAP_FIELD_ANY &&
|
|
sockaddr->satm_blli.Layer2Protocol == SAP_FIELD_ANY &&
|
|
sockaddr->satm_blli.Layer3Protocol == SAP_FIELD_ANY &&
|
|
sockaddr->satm_bhli.HighLayerInfoType == SAP_FIELD_ANY ) {
|
|
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
|
|
|
|
} else if ( sockaddr->satm_number.AddressType == SAP_FIELD_ABSENT ) {
|
|
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
|
|
|
|
} else {
|
|
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHGetSockaddrType
|
|
|
|
|
|
INT
|
|
WSHGetSocketInformation (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
OUT PCHAR OptionValue,
|
|
OUT PINT OptionLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves information about a socket for those socket
|
|
options supported in this helper DLL. Currently there are none
|
|
supported.
|
|
|
|
This is called by the winsock DLL when a level/option name
|
|
combination is passed to getsockopt() that the winsock DLL does
|
|
not understand.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're getting
|
|
information.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
Level - the level parameter passed to getsockopt().
|
|
|
|
OptionName - the optname parameter passed to getsockopt().
|
|
|
|
OptionValue - the optval parameter passed to getsockopt().
|
|
|
|
OptionLength - the optlen parameter passed to getsockopt().
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSHATM_SOCKET_CONTEXT context = HelperDllSocketContext;
|
|
INT err;
|
|
|
|
DBGPRINT(("GetSocketInformation: Level %d, OptionName %d, OptionLength %d\n",
|
|
Level, OptionName, *OptionLength));
|
|
|
|
UNREFERENCED_PARAMETER( SocketHandle );
|
|
UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
|
|
UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
|
|
|
|
//
|
|
// Check if this is an internal request for context information.
|
|
//
|
|
|
|
if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
|
|
|
|
//
|
|
// The Windows Sockets DLL is requesting context information
|
|
// from us. If an output buffer was not supplied, the Windows
|
|
// Sockets DLL is just requesting the size of our context
|
|
// information.
|
|
//
|
|
|
|
if ( OptionValue != NULL ) {
|
|
|
|
//
|
|
// Make sure that the buffer is sufficient to hold all the
|
|
// context information.
|
|
//
|
|
|
|
if ( *OptionLength < sizeof(*context) ) {
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
//
|
|
// Copy in the context information.
|
|
//
|
|
|
|
RtlCopyMemory( OptionValue, context, sizeof(*context) );
|
|
}
|
|
|
|
*OptionLength = sizeof(*context);
|
|
|
|
err = NO_ERROR;
|
|
|
|
} else {
|
|
|
|
switch ( OptionName ) {
|
|
|
|
case SO_MAX_MSG_SIZE:
|
|
|
|
if ( TdiConnectionObjectHandle == NULL ) {
|
|
|
|
DbgPrint("wshatm: SO_MAX_MSG_SIZE: immed return\n");
|
|
if ( *OptionLength >= sizeof(DWORD) ) {
|
|
|
|
*(LPDWORD)OptionValue = DEFAULT_RECEIVE_BUFFER_SIZE;
|
|
*OptionLength = sizeof(DWORD);
|
|
|
|
err = NO_ERROR;
|
|
|
|
} else {
|
|
|
|
err = WSAEFAULT;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DbgPrint("wshatm: SO_MAX_MSG_SIZE: querying driver\n");
|
|
err = AtmGetGenericObjectInformation(
|
|
TdiConnectionObjectHandle,
|
|
IOCTL_RWAN_GENERIC_CONN_HANDLE_QUERY,
|
|
RWAN_OID_CONN_OBJECT_MAX_MSG_SIZE,
|
|
NULL, // No Input buffer
|
|
0, // Input Buffer length
|
|
OptionValue, // Output buffer
|
|
*OptionLength, // Output buffer length
|
|
OptionLength // NumberOfBytesReturned
|
|
);
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
err = WSAENOPROTOOPT;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return err;
|
|
|
|
} // WSHGetSocketInformation
|
|
|
|
|
|
INT
|
|
WSHGetWildcardSockaddr (
|
|
IN PVOID HelperDllSocketContext,
|
|
OUT PSOCKADDR Sockaddr,
|
|
OUT PINT SockaddrLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a wildcard socket address. A wildcard address
|
|
is one which will bind the socket to an endpoint of the transport's
|
|
choosing. For ATM, a wildcard address has AddressType and BHLI and
|
|
BLLI Type fields set to SAP_FIELD_ANY.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket() for the socket for which we need a wildcard
|
|
address.
|
|
|
|
Sockaddr - points to a buffer which will receive the wildcard socket
|
|
address.
|
|
|
|
SockaddrLength - receives the length of the wioldcard sockaddr.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSOCKADDR_ATM sockaddr;
|
|
|
|
DBGPRINT(("GetWildcardAddress\n"));
|
|
|
|
sockaddr = (PSOCKADDR_ATM)Sockaddr;
|
|
|
|
if ( *SockaddrLength < sizeof(SOCKADDR_ATM) ) {
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
*SockaddrLength = sizeof(SOCKADDR_ATM);
|
|
|
|
|
|
//
|
|
// Prepare the ATM wild card address.
|
|
//
|
|
RtlZeroMemory( sockaddr, sizeof(SOCKADDR_ATM) );
|
|
|
|
sockaddr->satm_family = AF_ATM;
|
|
sockaddr->satm_number.AddressType = SAP_FIELD_ABSENT;
|
|
sockaddr->satm_blli.Layer2Protocol = SAP_FIELD_ANY;
|
|
sockaddr->satm_blli.Layer3Protocol = SAP_FIELD_ANY;
|
|
sockaddr->satm_bhli.HighLayerInfoType = SAP_FIELD_ANY;
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSAGetWildcardSockaddr
|
|
|
|
|
|
DWORD
|
|
WSHGetWinsockMapping (
|
|
OUT PWINSOCK_MAPPING Mapping,
|
|
IN DWORD MappingLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the list of address family/socket type/protocol triples
|
|
supported by this helper DLL.
|
|
|
|
Arguments:
|
|
|
|
Mapping - receives a pointer to a WINSOCK_MAPPING structure that
|
|
describes the triples supported here.
|
|
|
|
MappingLength - the length, in bytes, of the passed-in Mapping buffer.
|
|
|
|
Return Value:
|
|
|
|
DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
|
|
helper DLL. If the passed-in buffer is too small, the return
|
|
value will indicate the size of a buffer needed to contain
|
|
the WINSOCK_MAPPING structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD mappingLength;
|
|
|
|
DBGPRINT(("GetWinsockMapping\n"));
|
|
|
|
mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
|
|
sizeof(AtmMappingTriples);
|
|
|
|
//
|
|
// If the passed-in buffer is too small, return the length needed
|
|
// now without writing to the buffer. The caller should allocate
|
|
// enough memory and call this routine again.
|
|
//
|
|
|
|
if ( mappingLength > MappingLength ) {
|
|
return mappingLength;
|
|
}
|
|
|
|
//
|
|
// Fill in the output mapping buffer with the list of triples
|
|
// supported in this helper DLL.
|
|
//
|
|
|
|
Mapping->Rows = sizeof(AtmMappingTriples) / sizeof(AtmMappingTriples[0]);
|
|
Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
|
|
RtlMoveMemory(
|
|
Mapping->Mapping,
|
|
AtmMappingTriples,
|
|
sizeof(AtmMappingTriples)
|
|
);
|
|
|
|
//
|
|
// Return the number of bytes we wrote.
|
|
//
|
|
|
|
return mappingLength;
|
|
|
|
} // WSHGetWinsockMapping
|
|
|
|
|
|
INT
|
|
WSHOpenSocket (
|
|
IN OUT PINT AddressFamily,
|
|
IN OUT PINT SocketType,
|
|
IN OUT PINT Protocol,
|
|
OUT PUNICODE_STRING TransportDeviceName,
|
|
OUT PVOID *HelperDllSocketContext,
|
|
OUT PDWORD NotificationEvents
|
|
)
|
|
{
|
|
return WSHOpenSocket2(
|
|
AddressFamily,
|
|
SocketType,
|
|
Protocol,
|
|
0, // Group
|
|
0, // Flags
|
|
TransportDeviceName,
|
|
HelperDllSocketContext,
|
|
NotificationEvents
|
|
);
|
|
|
|
} // WSHOpenSocket
|
|
|
|
|
|
INT
|
|
WSHOpenSocket2 (
|
|
IN OUT PINT AddressFamily,
|
|
IN OUT PINT SocketType,
|
|
IN OUT PINT Protocol,
|
|
IN GROUP Group,
|
|
IN DWORD Flags,
|
|
OUT PUNICODE_STRING TransportDeviceName,
|
|
OUT PVOID *HelperDllSocketContext,
|
|
OUT PDWORD NotificationEvents
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the necessary work for this helper DLL to open a socket and is
|
|
called by the winsock DLL in the socket() routine. This routine
|
|
verifies that the specified triple is valid, determines the NT
|
|
device name of the TDI provider that will support that triple,
|
|
allocates space to hold the socket's context block, and
|
|
canonicalizes the triple.
|
|
|
|
Arguments:
|
|
|
|
AddressFamily - on input, the address family specified in the
|
|
socket() call. On output, the canonicalized value for the
|
|
address family.
|
|
|
|
SocketType - on input, the socket type specified in the socket()
|
|
call. On output, the canonicalized value for the socket type.
|
|
|
|
Protocol - on input, the protocol specified in the socket() call.
|
|
On output, the canonicalized value for the protocol.
|
|
|
|
Group - Identifies the group for the new socket.
|
|
|
|
Flags - Zero or more WSA_FLAG_* flags as passed into WSASocket().
|
|
|
|
TransportDeviceName - receives the name of the TDI provider that
|
|
will support the specified triple.
|
|
|
|
HelperDllSocketContext - receives a context pointer that the winsock
|
|
DLL will return to this helper DLL on future calls involving
|
|
this socket.
|
|
|
|
NotificationEvents - receives a bitmask of those state transitions
|
|
this helper DLL should be notified on.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSHATM_SOCKET_CONTEXT context;
|
|
DWORD multipointFlags;
|
|
UNICODE_STRING atmDeviceName;
|
|
|
|
//
|
|
// Determine whether this is an ATM socket.
|
|
//
|
|
|
|
DBGPRINT(("WSHOpenSocket2: AF %d, Type %d, Proto %d\n",
|
|
*AddressFamily, *SocketType, *Protocol));
|
|
|
|
if ( IsTripleInList(
|
|
AtmMappingTriples,
|
|
sizeof(AtmMappingTriples) / sizeof(AtmMappingTriples[0]),
|
|
*AddressFamily,
|
|
*SocketType,
|
|
*Protocol ) ) {
|
|
|
|
//
|
|
// It's an ATM socket. Check the flags.
|
|
//
|
|
|
|
if ( ( Flags & ~VALID_ATM_FLAGS ) != 0 ) {
|
|
|
|
DBGPRINT(("WSHOpenSocket2: Bad flags x%x\n", Flags));
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
if ( ( Flags & ATM_WSA_MULTIPOINT_FLAGS ) != 0 ) {
|
|
|
|
//
|
|
// The only multipoint combinations allowed are:
|
|
//
|
|
// 1. C_ROOT|D_ROOT
|
|
// 2. C_LEAF|D_LEAF
|
|
//
|
|
|
|
multipointFlags = ( Flags & ATM_WSA_MULTIPOINT_FLAGS );
|
|
|
|
if ( ( multipointFlags != (WSA_FLAG_MULTIPOINT_C_ROOT | WSA_FLAG_MULTIPOINT_D_ROOT) ) &&
|
|
( multipointFlags != (WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF) ) ) {
|
|
|
|
DBGPRINT(("WSHOpenSocket2: Bad multipoint flags x%x\n",
|
|
Flags));
|
|
|
|
return WSAEINVAL;
|
|
|
|
} else {
|
|
|
|
DBGPRINT(("WSHOpenSocket2: Good multipoint flags x%x\n", Flags));
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the canonical form of a ATM socket triple.
|
|
//
|
|
|
|
*AddressFamily = AtmMappingTriples[0].AddressFamily;
|
|
*SocketType = AtmMappingTriples[0].SocketType;
|
|
*Protocol = AtmMappingTriples[0].Protocol;
|
|
|
|
//
|
|
// Prepare the name of the TDI device.
|
|
//
|
|
|
|
RtlInitUnicodeString( &atmDeviceName, DD_ATM_DEVICE_NAME );
|
|
|
|
TransportDeviceName->Buffer = RTL_ALLOCATE_HEAP( RtlProcessHeap( ), 0, atmDeviceName.MaximumLength );
|
|
|
|
if ( TransportDeviceName->Buffer == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
TransportDeviceName->MaximumLength = atmDeviceName.MaximumLength;
|
|
TransportDeviceName->Length = 0;
|
|
|
|
RtlCopyUnicodeString(TransportDeviceName, &atmDeviceName);
|
|
|
|
} else {
|
|
|
|
//
|
|
// This should never happen if the registry information about this
|
|
// helper DLL is correct. If somehow this did happen, just return
|
|
// an error.
|
|
//
|
|
|
|
DBGPRINT(("WSHOpenSocket2: Triple not found!\n"));
|
|
|
|
if ( *Protocol != ATMPROTO_AAL5 ) {
|
|
|
|
return WSAEPROTONOSUPPORT;
|
|
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// Allocate context for this socket. The Windows Sockets DLL will
|
|
// return this value to us when it asks us to get/set socket options.
|
|
//
|
|
|
|
context = RTL_ALLOCATE_HEAP( RtlProcessHeap( ), 0, sizeof(*context) );
|
|
if ( context == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
//
|
|
// Initialize the context for the socket.
|
|
//
|
|
|
|
context->AddressFamily = *AddressFamily;
|
|
context->SocketType = *SocketType;
|
|
context->Protocol = *Protocol;
|
|
context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
|
|
context->Flags = Flags;
|
|
context->LocalFlags = 0;
|
|
|
|
//
|
|
// Tell the Windows Sockets DLL which state transitions we're
|
|
// interested in being notified of.
|
|
//
|
|
|
|
*NotificationEvents =
|
|
WSH_NOTIFY_BIND | WSH_NOTIFY_LISTEN | WSH_NOTIFY_CLOSE;
|
|
|
|
//
|
|
// Everything worked, return success.
|
|
//
|
|
|
|
*HelperDllSocketContext = context;
|
|
|
|
DBGPRINT(("WSHOpenSocket2 success: AF %d, Type %d, Proto %d\n",
|
|
*AddressFamily, *SocketType, *Protocol));
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHOpenSocket
|
|
|
|
|
|
INT
|
|
WSHNotify (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN DWORD NotifyEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the winsock DLL after a state transition
|
|
of the socket. Only state transitions returned in the
|
|
NotificationEvents parameter of WSHOpenSocket() are notified here.
|
|
This routine allows a winsock helper DLL to track the state of
|
|
socket and perform necessary actions corresponding to state
|
|
transitions.
|
|
|
|
If we see a LISTEN event, we call setsockopt() to force AFD to
|
|
allocate data buffers (for options) for incoming connection requests
|
|
on this socket.
|
|
|
|
If we see a BIND event for a socket to be used for multipoint
|
|
activity, we tell RAWWAN that the associated address object is
|
|
of multipoint type.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer given to the winsock
|
|
DLL by WSHOpenSocket().
|
|
|
|
SocketHandle - the handle for the socket.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
NotifyEvent - indicates the state transition for which we're being
|
|
called.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSHATM_SOCKET_CONTEXT context = HelperDllSocketContext;
|
|
INT err;
|
|
INT Option;
|
|
INT OptionLength = sizeof(Option);
|
|
PCHAR pOption = (PCHAR)&Option;
|
|
|
|
DBGPRINT(("Notify: Event = %d\n", NotifyEvent));
|
|
|
|
err = NO_ERROR;
|
|
|
|
switch (NotifyEvent)
|
|
{
|
|
case WSH_NOTIFY_BIND:
|
|
|
|
DBGPRINT(("NotifyBind: context %x, Flags %x, LocalFlags %x\n",
|
|
context, context->Flags, context->LocalFlags));
|
|
|
|
//
|
|
// Request the Winsock DLL to set the options.
|
|
//
|
|
Option = MAX_ATM_OPTIONS_LENGTH;
|
|
|
|
err = setsockopt(
|
|
SocketHandle,
|
|
SOL_SOCKET,
|
|
SO_CONNOPTLEN,
|
|
pOption,
|
|
OptionLength
|
|
);
|
|
|
|
if ( err != NO_ERROR ) {
|
|
|
|
DBGPRINT(("WSHATM: NotifyBind: setsockopt SO_CONNOPTLEN err %x\n", err));
|
|
break;
|
|
}
|
|
|
|
context->LocalFlags |= WSHATM_SOCK_IS_BOUND;
|
|
|
|
if ( ( context->Flags & ATM_WSA_MULTIPOINT_FLAGS ) != 0 ) {
|
|
|
|
//
|
|
// Prepare flags for RAWWAN.
|
|
//
|
|
Option = 0;
|
|
|
|
if ( context->Flags & WSA_FLAG_MULTIPOINT_C_ROOT ) {
|
|
|
|
Option |= RWAN_AOFLAG_C_ROOT;
|
|
|
|
}
|
|
|
|
if ( context->Flags & WSA_FLAG_MULTIPOINT_C_LEAF ) {
|
|
|
|
Option |= RWAN_AOFLAG_C_LEAF;
|
|
|
|
}
|
|
|
|
if ( context->Flags & WSA_FLAG_MULTIPOINT_D_ROOT ) {
|
|
|
|
Option |= RWAN_AOFLAG_D_ROOT;
|
|
|
|
}
|
|
|
|
if ( context->Flags & WSA_FLAG_MULTIPOINT_D_LEAF ) {
|
|
|
|
Option |= RWAN_AOFLAG_D_LEAF;
|
|
|
|
}
|
|
|
|
//
|
|
// Inform RAWWAN about the Multipoint nature of this
|
|
// Address Object.
|
|
//
|
|
err = AtmSetGenericObjectInformation(
|
|
TdiAddressObjectHandle,
|
|
IOCTL_RWAN_GENERIC_ADDR_HANDLE_SET,
|
|
RWAN_OID_ADDRESS_OBJECT_FLAGS,
|
|
&Option,
|
|
sizeof(Option)
|
|
);
|
|
|
|
DBGPRINT(("Notify: Bind Notify on PMP endpoint, Option x%x, ret = %d\n",
|
|
Option, err));
|
|
}
|
|
else if ( ( context->LocalFlags & WSHATM_SOCK_ASSOCIATE_PVC_PENDING ) ) {
|
|
|
|
DBGPRINT(("Notify: Bind Notify will Associate PVC\n"));
|
|
err = AtmDoAssociatePVC(
|
|
context,
|
|
TdiAddressObjectHandle
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case WSH_NOTIFY_CLOSE:
|
|
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, context );
|
|
break;
|
|
|
|
case WSH_NOTIFY_LISTEN:
|
|
//
|
|
// Request the Winsock DLL to set the options.
|
|
//
|
|
Option = MAX_ATM_OPTIONS_LENGTH;
|
|
|
|
err = setsockopt(
|
|
SocketHandle,
|
|
SOL_SOCKET,
|
|
SO_CONNOPTLEN,
|
|
pOption,
|
|
OptionLength
|
|
);
|
|
break;
|
|
|
|
default:
|
|
err = WSAEINVAL;
|
|
break;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
} // WSHNotify
|
|
|
|
|
|
INT
|
|
WSHSetSocketInformation (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
IN PCHAR OptionValue,
|
|
IN INT OptionLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information about a socket for those socket
|
|
options supported in this helper DLL. We don't support any
|
|
options at present.
|
|
|
|
This routine is called by the winsock DLL when a level/option
|
|
name combination is passed to setsockopt() that the winsock DLL
|
|
does not understand.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're getting
|
|
information.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
Level - the level parameter passed to setsockopt().
|
|
|
|
OptionName - the optname parameter passed to setsockopt().
|
|
|
|
OptionValue - the optval parameter passed to setsockopt().
|
|
|
|
OptionLength - the optlen parameter passed to setsockopt().
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSHATM_SOCKET_CONTEXT context = HelperDllSocketContext;
|
|
INT error;
|
|
INT optionValue;
|
|
|
|
UNREFERENCED_PARAMETER( SocketHandle );
|
|
UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
|
|
UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
|
|
|
|
DBGPRINT(("SetSocketInformation: Level %d, Option x%x\n", Level, OptionName));
|
|
|
|
//
|
|
// Check if this is an internal request for context information.
|
|
//
|
|
|
|
if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
|
|
|
|
//
|
|
// The Windows Sockets DLL is requesting that we set context
|
|
// information for a new socket. If the new socket was
|
|
// accept()'ed, then we have already been notified of the socket
|
|
// and HelperDllSocketContext will be valid. If the new socket
|
|
// was inherited or duped into this process, then this is our
|
|
// first notification of the socket and HelperDllSocketContext
|
|
// will be equal to NULL.
|
|
//
|
|
// Insure that the context information being passed to us is
|
|
// sufficiently large.
|
|
//
|
|
|
|
if ( OptionLength < sizeof(*context) ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
if ( HelperDllSocketContext == NULL ) {
|
|
|
|
//
|
|
// This is our notification that a socket handle was
|
|
// inherited or duped into this process. Allocate a context
|
|
// structure for the new socket.
|
|
//
|
|
|
|
context = RTL_ALLOCATE_HEAP( RtlProcessHeap( ), 0, sizeof(*context) );
|
|
if ( context == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
//
|
|
// Copy over information into the context block.
|
|
//
|
|
|
|
RtlCopyMemory( context, OptionValue, sizeof(*context) );
|
|
context->SocketHandle = SocketHandle;
|
|
|
|
//
|
|
// Tell the Windows Sockets DLL where our context information is
|
|
// stored so that it can return the context pointer in future
|
|
// calls.
|
|
//
|
|
|
|
*(PWSHATM_SOCKET_CONTEXT *)OptionValue = context;
|
|
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
|
|
PWSHATM_SOCKET_CONTEXT parentContext;
|
|
INT one = 1;
|
|
INT zero = 0;
|
|
|
|
//
|
|
// The socket was accept()'ed and it needs to have the same
|
|
// properties as it's parent. The OptionValue buffer
|
|
// contains the context information of this socket's parent.
|
|
//
|
|
|
|
parentContext = (PWSHATM_SOCKET_CONTEXT)OptionValue;
|
|
|
|
ASSERT( context->AddressFamily == parentContext->AddressFamily );
|
|
ASSERT( context->SocketType == parentContext->SocketType );
|
|
ASSERT( context->Protocol == parentContext->Protocol );
|
|
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
return WSAENOPROTOOPT;
|
|
|
|
#if 0
|
|
//
|
|
// Handle socket-level options.
|
|
//
|
|
optionValue = *OptionValue;
|
|
|
|
switch ( OptionName ) {
|
|
|
|
case SO_RCVBUF:
|
|
|
|
context->ReceiveBufferSize = optionValue;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return WSAENOPROTOOPT;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
#endif
|
|
|
|
} // WSHSetSocketInformation
|
|
|
|
|
|
INT
|
|
WSHEnumProtocols (
|
|
IN LPINT lpiProtocols,
|
|
IN LPWSTR lpTransportKeyName,
|
|
IN OUT LPVOID lpProtocolBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerates the protocols supported by this helper.
|
|
|
|
Arguments:
|
|
|
|
lpiProtocols - Pointer to a NULL-terminated array of protocol
|
|
identifiers. Only protocols specified in this array will
|
|
be returned by this function. If this pointer is NULL,
|
|
all protocols are returned.
|
|
|
|
lpTransportKeyName -
|
|
|
|
lpProtocolBuffer - Pointer to a buffer to fill with PROTOCOL_INFO
|
|
structures.
|
|
|
|
lpdwBufferLength - Pointer to a variable that, on input, contains
|
|
the size of lpProtocolBuffer. On output, this value will be
|
|
updated with the size of the data actually written to the buffer.
|
|
|
|
Return Value:
|
|
|
|
INT - The number of protocols returned if successful, -1 if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD bytesRequired;
|
|
PPROTOCOL_INFO atmProtocolInfo;
|
|
PPROTOCOL_INFO udpProtocolInfo;
|
|
BOOL useAtm = FALSE;
|
|
DWORD i;
|
|
|
|
lpTransportKeyName; // Avoid compiler warnings.
|
|
|
|
DBGPRINT(("EnumProtocols\n"));
|
|
|
|
//
|
|
// Make sure that the caller cares about ATM.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
|
|
|
|
for ( i = 0; lpiProtocols[i] != 0; i++ ) {
|
|
if ( lpiProtocols[i] == ATMPROTO_AAL5 ) {
|
|
useAtm = TRUE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
useAtm = TRUE;
|
|
}
|
|
|
|
if ( !useAtm ) {
|
|
*lpdwBufferLength = 0;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Make sure that the caller has specified a sufficiently large
|
|
// buffer.
|
|
//
|
|
|
|
bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 1) +
|
|
( (wcslen( ATM_NAME ) + 1) * sizeof(WCHAR)));
|
|
|
|
if ( bytesRequired > *lpdwBufferLength ) {
|
|
*lpdwBufferLength = bytesRequired;
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Fill in ATM info, if requested.
|
|
//
|
|
|
|
if ( useAtm ) {
|
|
|
|
atmProtocolInfo = lpProtocolBuffer;
|
|
|
|
atmProtocolInfo->dwServiceFlags = XP_GUARANTEED_ORDER |
|
|
XP_MESSAGE_ORIENTED |
|
|
XP_SUPPORTS_MULTICAST |
|
|
XP_BANDWIDTH_ALLOCATION ;
|
|
atmProtocolInfo->iAddressFamily = AF_ATM;
|
|
atmProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_ATM);
|
|
atmProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_ATM);
|
|
atmProtocolInfo->iSocketType = ATM_AAL5_SOCK_TYPE;
|
|
atmProtocolInfo->iProtocol = ATMPROTO_AAL5;
|
|
atmProtocolInfo->dwMessageSize = 1;
|
|
atmProtocolInfo->lpProtocol = (LPWSTR)
|
|
( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
|
|
( (wcslen( ATM_NAME ) + 1) * sizeof(WCHAR) ) );
|
|
wcscpy( atmProtocolInfo->lpProtocol, ATM_NAME );
|
|
|
|
DBGPRINT(("EnumProtocols: lpProtocolBuffer %x, lpProtocol %x, BufLen %d\n",
|
|
lpProtocolBuffer,
|
|
atmProtocolInfo->lpProtocol,
|
|
*lpdwBufferLength));
|
|
|
|
}
|
|
|
|
*lpdwBufferLength = bytesRequired;
|
|
|
|
return (1);
|
|
|
|
} // WSHEnumProtocols
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsTripleInList (
|
|
IN PMAPPING_TRIPLE List,
|
|
IN ULONG ListLength,
|
|
IN INT AddressFamily,
|
|
IN INT SocketType,
|
|
IN INT Protocol
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether the specified triple has an exact match in the
|
|
list of triples.
|
|
|
|
Arguments:
|
|
|
|
List - a list of triples (address family/socket type/protocol) to
|
|
search.
|
|
|
|
ListLength - the number of triples in the list.
|
|
|
|
AddressFamily - the address family to look for in the list.
|
|
|
|
SocketType - the socket type to look for in the list.
|
|
|
|
Protocol - the protocol to look for in the list.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the triple was found in the list, false if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
//
|
|
// Walk through the list searching for an exact match.
|
|
//
|
|
|
|
for ( i = 0; i < ListLength; i++ ) {
|
|
|
|
//
|
|
// If all three elements of the triple match, return indicating
|
|
// that the triple did exist in the list.
|
|
//
|
|
|
|
if ( AddressFamily == List[i].AddressFamily &&
|
|
SocketType == List[i].SocketType &&
|
|
Protocol == List[i].Protocol
|
|
) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The triple was not found in the list.
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
} // IsTripleInList
|
|
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHJoinLeaf (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN PVOID LeafHelperDllSocketContext,
|
|
IN SOCKET LeafSocketHandle,
|
|
IN PSOCKADDR Sockaddr,
|
|
IN DWORD SockaddrLength,
|
|
IN LPWSABUF CallerData,
|
|
IN LPWSABUF CalleeData,
|
|
IN LPQOS SocketQOS,
|
|
IN LPQOS GroupQOS,
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs the protocol-dependent portion of creating a multicast
|
|
socket.
|
|
|
|
TBD: Needs a Lot Of Work!
|
|
|
|
Arguments:
|
|
|
|
The following four parameters correspond to the socket passed into
|
|
the WSAJoinLeaf() API:
|
|
|
|
HelperDllSocketContext - The context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - The handle of the socket used to establish the
|
|
multicast "session".
|
|
|
|
TdiAddressObjectHandle - The TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - The TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
The next two parameters correspond to the newly created socket that
|
|
identifies the multicast "session":
|
|
|
|
LeafHelperDllSocketContext - The context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
LeafSocketHandle - The handle of the socket that identifies the
|
|
multicast "session".
|
|
|
|
Sockaddr - The name of the peer to which the socket is to be joined.
|
|
|
|
SockaddrLength - The length of Sockaddr.
|
|
|
|
CallerData - Pointer to user data to be transferred to the peer
|
|
during multipoint session establishment.
|
|
|
|
CalleeData - Pointer to user data to be transferred back from
|
|
the peer during multipoint session establishment.
|
|
|
|
SocketQOS - Pointer to the flowspecs for SocketHandle, one in each
|
|
direction.
|
|
|
|
GroupQOS - Pointer to the flowspecs for the socket group, if any.
|
|
|
|
Flags - Flags to indicate if the socket is acting as sender,
|
|
receiver, or both.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, a WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
INT err;
|
|
|
|
if( Flags != JL_SENDER_ONLY ) {
|
|
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
if (SocketQOS)
|
|
{
|
|
err = WSHAtmSetQoS(
|
|
LeafHelperDllSocketContext,
|
|
LeafSocketHandle,
|
|
SocketQOS,
|
|
sizeof(*SocketQOS)
|
|
);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHJoinLeaf
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHGetBroadcastSockaddr (
|
|
IN PVOID HelperDllSocketContext,
|
|
OUT PSOCKADDR Sockaddr,
|
|
OUT PINT SockaddrLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a broadcast socket address. A broadcast address
|
|
may be used as a destination for the sendto() API to send a datagram
|
|
to all interested clients.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket() for the socket for which we need a broadcast
|
|
address.
|
|
|
|
Sockaddr - points to a buffer which will receive the broadcast socket
|
|
address.
|
|
|
|
SockaddrLength - receives the length of the broadcast sockaddr.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if 1
|
|
return WSAEINVAL;
|
|
#else
|
|
|
|
LPSOCKADDR_ATM addr;
|
|
|
|
if( *SockaddrLength < sizeof(SOCKADDR_ATM) ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
*SockaddrLength = sizeof(SOCKADDR_ATM);
|
|
|
|
//
|
|
// Build the broadcast address.
|
|
//
|
|
|
|
addr = (LPSOCKADDR_ATM)Sockaddr;
|
|
|
|
RtlZeroMemory(
|
|
addr,
|
|
sizeof(*addr)
|
|
);
|
|
|
|
addr->satm_family = AF_ATM;
|
|
addr->satm_number.s_addr = htonl( INADDR_BROADCAST );
|
|
|
|
return NO_ERROR;
|
|
#endif // 1
|
|
|
|
} // WSAGetBroadcastSockaddr
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHGetWSAProtocolInfo (
|
|
IN LPWSTR ProviderName,
|
|
OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
|
|
OUT LPDWORD ProtocolInfoEntries
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
|
|
the protocol(s) supported by this helper.
|
|
|
|
Arguments:
|
|
|
|
ProviderName - Contains the name of the provider, such as "RawWan".
|
|
|
|
ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
|
|
|
|
ProtocolInfoEntries - Receives the number of entries in the array.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if( ProviderName == NULL ||
|
|
ProtocolInfo == NULL ||
|
|
ProtocolInfoEntries == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
DBGPRINT(("WSHGetWSAProtocolInfo: Provider Name: %ws\n", ProviderName));
|
|
|
|
if( _wcsicmp( ProviderName, L"RawWan" ) == 0 ) {
|
|
|
|
*ProtocolInfo = Winsock2Protocols;
|
|
*ProtocolInfoEntries = NUM_WINSOCK2_PROTOCOLS;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
|
|
} // WSHGetWSAProtocolInfo
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHAddressToString (
|
|
IN LPSOCKADDR Address,
|
|
IN INT AddressLength,
|
|
IN LPWSAPROTOCOL_INFOW ProtocolInfo,
|
|
OUT LPWSTR AddressString,
|
|
IN OUT LPDWORD AddressStringLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a SOCKADDR to a human-readable form.
|
|
|
|
Arguments:
|
|
|
|
Address - The SOCKADDR to convert.
|
|
|
|
AddressLength - The length of Address.
|
|
|
|
ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
|
|
|
|
AddressString - Receives the formatted address string.
|
|
|
|
AddressStringLength - On input, contains the length of AddressString.
|
|
On output, contains the number of characters actually written
|
|
to AddressString.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
WCHAR string[64];
|
|
PWCHAR pstring;
|
|
INT length; // Number of WCHARs filled into string
|
|
UINT i;
|
|
LPSOCKADDR_ATM addr;
|
|
UCHAR Val;
|
|
|
|
//
|
|
// Quick sanity checks.
|
|
//
|
|
|
|
if( Address == NULL ||
|
|
AddressLength < sizeof(SOCKADDR_ATM) ||
|
|
AddressString == NULL ||
|
|
AddressStringLength == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
addr = (LPSOCKADDR_ATM)Address;
|
|
|
|
if( addr->satm_family != AF_ATM ) {
|
|
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
if ( addr->satm_number.NumofDigits > ATM_ADDR_SIZE ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// Do the conversion.
|
|
//
|
|
length = 0;
|
|
pstring = string;
|
|
|
|
//
|
|
// If this is an E.164 address, prepend a '+'.
|
|
// Each entry in the array in satm_number consists of one
|
|
// digit coded in IA5 (ANSI).
|
|
//
|
|
if ( addr->satm_number.AddressType == ATM_E164 ) {
|
|
|
|
*pstring++ = L'+';
|
|
length++;
|
|
|
|
for ( i = 0; i < addr->satm_number.NumofDigits; i++ ) {
|
|
|
|
if ( !iswdigit(addr->satm_number.Addr[i]) ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
*pstring++ = ANSI_TO_WCHAR(addr->satm_number.Addr[i]);
|
|
}
|
|
|
|
length += addr->satm_number.NumofDigits;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This must be NSAP format. Each entry in the array
|
|
// is a full hex byte (two BCD digits). We'll unpack
|
|
// each array entry into two characters.
|
|
//
|
|
for ( i = 0; i < addr->satm_number.NumofDigits; i++ ) {
|
|
|
|
Val = (addr->satm_number.Addr[i] >> 4);
|
|
*pstring++ = DIGIT_TO_WCHAR(Val);
|
|
|
|
Val = (addr->satm_number.Addr[i] & 0xf);
|
|
*pstring++ = DIGIT_TO_WCHAR(Val);
|
|
}
|
|
|
|
length += (2 * addr->satm_number.NumofDigits);
|
|
}
|
|
|
|
//
|
|
// Terminate the string.
|
|
//
|
|
*pstring = L'\0';
|
|
|
|
length++; // account for terminator
|
|
|
|
if( *AddressStringLength < (DWORD)length ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
*AddressStringLength = (DWORD)length;
|
|
|
|
RtlCopyMemory(
|
|
AddressString,
|
|
string,
|
|
length * sizeof(WCHAR)
|
|
);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHAddressToString
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHStringToAddress (
|
|
IN LPWSTR AddressString,
|
|
IN DWORD AddressFamily,
|
|
IN LPWSAPROTOCOL_INFOW ProtocolInfo,
|
|
OUT LPSOCKADDR Address,
|
|
IN OUT LPINT AddressLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills in a SOCKADDR structure by parsing a human-readable string.
|
|
|
|
Arguments:
|
|
|
|
AddressString - Points to the zero-terminated human-readable string.
|
|
|
|
AddressFamily - The address family to which the string belongs.
|
|
|
|
ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
|
|
|
|
Address - Receives the SOCKADDR structure.
|
|
|
|
AddressLength - On input, contains the length of Address. On output,
|
|
contains the number of bytes actually written to Address.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR string[2*ATM_ADDR_SIZE+1];
|
|
UNICODE_STRING unistring;
|
|
CHAR ansistring[2*ATM_ADDR_SIZE+1];
|
|
ANSI_STRING ansstring;
|
|
PCHAR src;
|
|
PCHAR dst;
|
|
LPWSTR terminator;
|
|
LPSOCKADDR_ATM addr;
|
|
PWCHAR s, d;
|
|
INT numDigits, i;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Quick sanity checks.
|
|
//
|
|
|
|
if( AddressString == NULL ||
|
|
Address == NULL ||
|
|
AddressLength == NULL ||
|
|
*AddressLength < sizeof(SOCKADDR_ATM) ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
if( AddressFamily != AF_ATM ) {
|
|
|
|
DBGPRINT(("StrToAddr: invalid addrfam %d\n", AddressFamily));
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
|
|
addr = (LPSOCKADDR_ATM)Address;
|
|
RtlZeroMemory(
|
|
Address,
|
|
sizeof(SOCKADDR_ATM)
|
|
);
|
|
|
|
//
|
|
// Strip off all punctuation characters (spaces and periods).
|
|
//
|
|
for ( numDigits = 0, s = AddressString, d = string;
|
|
(numDigits <= sizeof(WCHAR)*ATM_ADDR_SIZE) && (*s != L'\0');
|
|
s++ ) {
|
|
|
|
if ( *s == ATM_ADDR_BLANK_CHAR ||
|
|
*s == ATM_ADDR_PUNCTUATION_CHAR ) {
|
|
continue;
|
|
}
|
|
|
|
*d++ = *s;
|
|
numDigits ++;
|
|
}
|
|
|
|
if ( numDigits == 0 ) {
|
|
|
|
DBGPRINT(("StrToAddr[%ws]: numdigits after stripping is 0!\n",
|
|
AddressString));
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// Terminate it and convert into Unicode string.
|
|
//
|
|
*d = L'\0';
|
|
|
|
RtlInitUnicodeString(&unistring, string);
|
|
|
|
//
|
|
// Convert it into an ANSI string.
|
|
//
|
|
ansstring.Buffer = ansistring;
|
|
ansstring.MaximumLength = 2*ATM_ADDR_SIZE + 1;
|
|
ansstring.Length = 0;
|
|
|
|
status = RtlUnicodeStringToAnsiString(&ansstring, &unistring, FALSE);
|
|
|
|
if ( status != STATUS_SUCCESS ) {
|
|
DBGPRINT(("StrToAddr[%ws]: RtlUnicodeToAnsi failed (%x)\n",
|
|
string, status));
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
addr->satm_family = AF_ATM;
|
|
|
|
src = ansistring;
|
|
|
|
if ( *src == ATM_ADDR_E164_START_CHAR ) {
|
|
|
|
src ++;
|
|
numDigits --;
|
|
|
|
if ( numDigits == 0 ) {
|
|
DBGPRINT(("StrToAddr[%ws]: AnsiString:[%s], numDigits is 0!\n",
|
|
string, ansistring));
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
addr->satm_number.AddressType = ATM_E164;
|
|
addr->satm_number.NumofDigits = numDigits;
|
|
|
|
RtlCopyMemory(addr->satm_number.Addr, src, numDigits);
|
|
|
|
} else {
|
|
|
|
UCHAR hexString[3];
|
|
ULONG Val;
|
|
|
|
hexString[2] = 0;
|
|
|
|
if ( numDigits != 2 * ATM_ADDR_SIZE ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
addr->satm_number.AddressType = ATM_NSAP;
|
|
addr->satm_number.NumofDigits = numDigits/2;
|
|
|
|
for ( i = 0; i < ATM_ADDR_SIZE; i++ ) {
|
|
|
|
hexString[0] = *src++;
|
|
hexString[1] = *src++;
|
|
|
|
status = RtlCharToInteger(hexString, 16, &Val);
|
|
|
|
if ( status != STATUS_SUCCESS ) {
|
|
DBGPRINT(("StrToAtm[%ws]: index %d, hexString: %s, CharToInt %x\n",
|
|
string, hexString, status));
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
addr->satm_number.Addr[i] = (UCHAR)Val;
|
|
}
|
|
|
|
}
|
|
|
|
addr->satm_blli.Layer2Protocol = SAP_FIELD_ABSENT;
|
|
addr->satm_blli.Layer3Protocol = SAP_FIELD_ABSENT;
|
|
addr->satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;
|
|
|
|
*AddressLength = sizeof(SOCKADDR_ATM);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHStringToAddress
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHGetProviderGuid (
|
|
IN LPWSTR ProviderName,
|
|
OUT LPGUID ProviderGuid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the GUID identifying the protocols supported by this helper.
|
|
|
|
Arguments:
|
|
|
|
ProviderName - Contains the name of the provider, such as "RawWan".
|
|
|
|
ProviderGuid - Points to a buffer that receives the provider's GUID.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if( ProviderName == NULL ||
|
|
ProviderGuid == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
if( _wcsicmp( ProviderName, RWAN_NAME ) == 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
ProviderGuid,
|
|
&AtmProviderGuid,
|
|
sizeof(GUID)
|
|
);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
|
|
} // WSHGetProviderGuid
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
WSHIoctl (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN DWORD IoControlCode,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned,
|
|
IN LPWSAOVERLAPPED Overlapped,
|
|
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
|
|
OUT LPBOOL NeedsCompletion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs queries & controls on the socket. This is basically an
|
|
"escape hatch" for IOCTLs not supported by MSAFD.DLL. Any unknown
|
|
IOCTLs are routed to the socket's helper DLL for protocol-specific
|
|
processing.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're controlling.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
IoControlCode - Control code of the operation to perform.
|
|
|
|
InputBuffer - Address of the input buffer.
|
|
|
|
InputBufferLength - The length of InputBuffer.
|
|
|
|
OutputBuffer - Address of the output buffer.
|
|
|
|
OutputBufferLength - The length of OutputBuffer.
|
|
|
|
NumberOfBytesReturned - Receives the number of bytes actually written
|
|
to the output buffer.
|
|
|
|
Overlapped - Pointer to a WSAOVERLAPPED structure for overlapped
|
|
operations.
|
|
|
|
CompletionRoutine - Pointer to a completion routine to call when
|
|
the operation is completed.
|
|
|
|
NeedsCompletion - WSAIoctl() can be overlapped, with all the gory
|
|
details that involves, such as setting events, queuing completion
|
|
routines, and posting to IO completion ports. Since the majority
|
|
of the IOCTL codes can be completed quickly "in-line", MSAFD.DLL
|
|
can optionally perform the overlapped completion of the operation.
|
|
|
|
Setting *NeedsCompletion to TRUE (the default) causes MSAFD.DLL
|
|
to handle all of the IO completion details iff this is an
|
|
overlapped operation on an overlapped socket.
|
|
|
|
Setting *NeedsCompletion to FALSE tells MSAFD.DLL to take no
|
|
further action because the helper DLL will perform any necessary
|
|
IO completion.
|
|
|
|
Note that if a helper performs its own IO completion, the helper
|
|
is responsible for maintaining the "overlapped" mode of the socket
|
|
at socket creation time and NOT performing overlapped IO completion
|
|
on non-overlapped sockets.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
INT err;
|
|
PWSHATM_SOCKET_CONTEXT context;
|
|
|
|
//
|
|
// Quick sanity checks.
|
|
//
|
|
|
|
if( HelperDllSocketContext == NULL ||
|
|
SocketHandle == INVALID_SOCKET ||
|
|
NumberOfBytesReturned == NULL ||
|
|
NeedsCompletion == NULL ) {
|
|
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
context = (PWSHATM_SOCKET_CONTEXT)HelperDllSocketContext;
|
|
*NeedsCompletion = TRUE;
|
|
|
|
DBGPRINT(("WSHIoctl: IoControlCode x%x, InBuf: x%x/%d, OutBuf: x%x/%d\n",
|
|
IoControlCode,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength));
|
|
|
|
switch (IoControlCode) {
|
|
|
|
case SIO_ASSOCIATE_PVC:
|
|
|
|
context->SocketHandle = SocketHandle;
|
|
err = AtmAssociatePVC(
|
|
SocketHandle,
|
|
HelperDllSocketContext,
|
|
TdiAddressObjectHandle,
|
|
TdiConnectionObjectHandle,
|
|
InputBuffer,
|
|
InputBufferLength
|
|
);
|
|
|
|
DBGPRINT(("WSHIoctl: ASSOCIATE_PVC: context %x, LocalFlags %x, err %d\n",
|
|
context, context->LocalFlags, err));
|
|
|
|
if ( (err == NO_ERROR) &&
|
|
(( context->LocalFlags & WSHATM_SOCK_IS_BOUND ) == 0 )) {
|
|
|
|
SOCKADDR_ATM addr;
|
|
INT len = sizeof(addr);
|
|
|
|
(VOID) WSHGetWildcardSockaddr (
|
|
HelperDllSocketContext,
|
|
(struct sockaddr *)&addr,
|
|
&len);
|
|
|
|
DBGPRINT(("WSHIoctl: ASSOCIATE_PVC: will bind\n"));
|
|
err = bind(SocketHandle, (struct sockaddr *)&addr, len);
|
|
|
|
#if DBG
|
|
if ( err != NO_ERROR ) {
|
|
|
|
DbgPrint("WSHATM: bind err %d, context %x, LocalFlags %x\n",
|
|
err, context, context->LocalFlags);
|
|
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
if ( err == NO_ERROR ) {
|
|
|
|
SOCKADDR_ATM addr;
|
|
INT len = sizeof(addr);
|
|
|
|
(VOID) WSHGetWildcardSockaddr (
|
|
HelperDllSocketContext,
|
|
(struct sockaddr *)&addr,
|
|
&len);
|
|
|
|
addr.satm_family = AF_ATM;
|
|
addr.satm_number.AddressType = ATM_NSAP;
|
|
addr.satm_number.NumofDigits = ATM_ADDR_SIZE;
|
|
|
|
err = WSAConnect(
|
|
SocketHandle,
|
|
(struct sockaddr *)&addr,
|
|
len,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
|
|
if ( err != NO_ERROR ) {
|
|
DBGPRINT(("WSHIoctl: connect (%d) returned %d\n",
|
|
SocketHandle, err));
|
|
|
|
if ( err == SOCKET_ERROR ) {
|
|
err = WSAGetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SIO_SET_QOS:
|
|
err = WSHAtmSetQoS(
|
|
HelperDllSocketContext,
|
|
SocketHandle,
|
|
InputBuffer,
|
|
InputBufferLength
|
|
);
|
|
break;
|
|
|
|
case SIO_GET_QOS:
|
|
err = WSHAtmGetQoS(
|
|
HelperDllSocketContext,
|
|
SocketHandle,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
NumberOfBytesReturned
|
|
);
|
|
break;
|
|
|
|
case SIO_GET_GROUP_QOS:
|
|
*NumberOfBytesReturned = 0;
|
|
err = NO_ERROR;
|
|
break;
|
|
|
|
case SIO_SET_GROUP_QOS:
|
|
*NumberOfBytesReturned = 0;
|
|
err = WSAEOPNOTSUPP;
|
|
break;
|
|
|
|
case SIO_GET_NUMBER_OF_ATM_DEVICES:
|
|
err = AtmQueryAtmGlobalInformation(
|
|
ATMSP_OID_NUMBER_OF_DEVICES,
|
|
NULL,
|
|
0,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
NumberOfBytesReturned
|
|
);
|
|
break;
|
|
|
|
case SIO_GET_ATM_ADDRESS:
|
|
err = AtmQueryAtmGlobalInformation(
|
|
ATMSP_OID_ATM_ADDRESS,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
NumberOfBytesReturned
|
|
);
|
|
break;
|
|
|
|
case SIO_GET_ATM_CONNECTION_ID:
|
|
|
|
if ( TdiConnectionObjectHandle == NULL ) {
|
|
|
|
//
|
|
// Check if this is a PVC. If so, the Connection ID is
|
|
// available locally.
|
|
//
|
|
if ( context && ( context->LocalFlags & WSHATM_SOCK_IS_PVC )) {
|
|
|
|
if ( ( OutputBuffer != NULL ) &&
|
|
( OutputBufferLength >= sizeof(ATM_CONNECTION_ID) ) ) {
|
|
|
|
ATM_CONNECTION_ID * pConnId = OutputBuffer;
|
|
|
|
*pConnId = context->ConnectionId;
|
|
|
|
err = NO_ERROR;
|
|
|
|
} else {
|
|
|
|
err = WSAEFAULT;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = WSAENOTCONN;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = AtmGetAtmObjectInformation(
|
|
TdiConnectionObjectHandle,
|
|
IOCTL_RWAN_MEDIA_SPECIFIC_CONN_HANDLE_QUERY,
|
|
ATMSP_OID_CONNECTION_ID,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
NumberOfBytesReturned
|
|
);
|
|
}
|
|
break;
|
|
|
|
case SIO_ENABLE_CIRCULAR_QUEUEING:
|
|
err = NO_ERROR;
|
|
break;
|
|
|
|
default:
|
|
err = WSAEINVAL;
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(("WSHIoctl: IoControlCode x%x, returning %d\n",
|
|
IoControlCode, err));
|
|
|
|
return err;
|
|
|
|
} // WSHIoctl
|
|
|
|
|
|
|
|
INT
|
|
WSHAtmSetQoS(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to process a SIO_SET_QOS Ioctl. The QoS is represented
|
|
by a basic QOS structure, and an optional provider-specific part. We first
|
|
copy this two-part structure into a single flat buffer, and then call
|
|
setsockopt(SO_CONNOPT) to get MSAFD to copy this down to AFD. Later, if/when
|
|
a WSAConnect() is made, AFD will pass these "connection options" in the TDI
|
|
connect to the transport.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're controlling.
|
|
|
|
InputBuffer - Address of the input buffer.
|
|
|
|
InputBufferLength - The length of InputBuffer.
|
|
|
|
Return Value:
|
|
|
|
INT - The completion status.
|
|
|
|
--*/
|
|
{
|
|
INT err;
|
|
LPQOS lpQOS;
|
|
|
|
PUCHAR pQoSBuffer; // Flat buffer for use in SO_CONNOPT
|
|
INT QoSBufferLength;
|
|
LPQOS lpOutputQOS;
|
|
|
|
err = NO_ERROR;
|
|
lpQOS = (LPQOS)InputBuffer;
|
|
|
|
DBGPRINT(("SetQoS: Context x%x, Handle x%x, InBuf x%x, InBufLen %d\n",
|
|
HelperDllSocketContext,
|
|
SocketHandle,
|
|
InputBuffer,
|
|
InputBufferLength));
|
|
do
|
|
{
|
|
if (lpQOS == NULL)
|
|
{
|
|
err = WSAEINVAL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Expect atleast the base QOS structure to be present.
|
|
//
|
|
if (InputBufferLength < sizeof(*lpQOS))
|
|
{
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Sanity check the provider-specific part.
|
|
//
|
|
if (((lpQOS->ProviderSpecific.buf != NULL) &&
|
|
(lpQOS->ProviderSpecific.len == 0))
|
|
||
|
|
((lpQOS->ProviderSpecific.buf == NULL) &&
|
|
(lpQOS->ProviderSpecific.len != 0)))
|
|
{
|
|
DBGPRINT(("lpQOS %x, buf %x, len %x, not consistent\n",
|
|
lpQOS, lpQOS->ProviderSpecific.buf,
|
|
lpQOS->ProviderSpecific.len));
|
|
|
|
err = WSAEINVAL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Compute the total length we need.
|
|
//
|
|
QoSBufferLength = sizeof(QOS) + lpQOS->ProviderSpecific.len;
|
|
|
|
pQoSBuffer = RTL_ALLOCATE_HEAP(RtlProcessHeap(), 0, QoSBufferLength);
|
|
|
|
if (pQoSBuffer == NULL)
|
|
{
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
lpOutputQOS = (LPQOS)pQoSBuffer;
|
|
|
|
//
|
|
// Copy in the generic QOS part.
|
|
//
|
|
RtlCopyMemory(
|
|
lpOutputQOS,
|
|
lpQOS,
|
|
sizeof(QOS)
|
|
);
|
|
|
|
//
|
|
// Copy in the provider-specific QOS just after the generic part.
|
|
//
|
|
if (lpQOS->ProviderSpecific.len != 0)
|
|
{
|
|
RtlCopyMemory(
|
|
(PCHAR)pQoSBuffer+sizeof(QOS),
|
|
lpQOS->ProviderSpecific.buf,
|
|
lpQOS->ProviderSpecific.len
|
|
);
|
|
|
|
//
|
|
// Set up the offset to provider-specific part. Note that we
|
|
// use the "buf" to mean the offset from the beginning of the
|
|
// flat QOS buffer and not a pointer.
|
|
//
|
|
lpOutputQOS->ProviderSpecific.buf = (char FAR *)sizeof(QOS);
|
|
}
|
|
else
|
|
{
|
|
lpOutputQOS->ProviderSpecific.buf = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Request the Winsock DLL to set the options.
|
|
//
|
|
err = setsockopt(
|
|
SocketHandle,
|
|
SOL_SOCKET,
|
|
SO_CONNOPT,
|
|
pQoSBuffer,
|
|
QoSBufferLength
|
|
);
|
|
|
|
RTL_FREE_HEAP(
|
|
RtlProcessHeap(),
|
|
0,
|
|
pQoSBuffer
|
|
);
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
DBGPRINT(("SetQoS: returning err %d\n", err));
|
|
return (err);
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
WSHAtmGetQoS(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to process a SIO_GET_QOS Ioctl. We translate
|
|
this to a "Get Connect Options" and ask MSAFD to get them for us.
|
|
The connect options for ATM will contain the base QoS structure and
|
|
optionally a provider-specific part that contains additional information
|
|
elements.
|
|
|
|
One of the places this might be called is when processing a WSAAccept
|
|
with a condition function specified. MSAFD calls us to get the QoS,
|
|
and we in turn request MSAFD to get SO_CONNOPT.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're controlling.
|
|
|
|
OutputBuffer - Address of the Output buffer.
|
|
|
|
OutputBufferLength - The length of OutputBuffer.
|
|
|
|
NumberOfBytesReturned - where we return the number of bytes we filled into
|
|
OutputBuffer.
|
|
|
|
Return Value:
|
|
|
|
INT - The completion status.
|
|
|
|
--*/
|
|
{
|
|
INT err;
|
|
DWORD BytesReturned;
|
|
LPQOS lpQOS;
|
|
|
|
err = NO_ERROR;
|
|
|
|
DBGPRINT(("GetQoS: Context x%x, Handle x%x, OutBuf x%x, OutBufLen %d\n",
|
|
HelperDllSocketContext,
|
|
SocketHandle,
|
|
OutputBuffer,
|
|
OutputBufferLength));
|
|
|
|
do
|
|
{
|
|
//
|
|
// Expect atleast enough space to fit in the base QoS structure.
|
|
//
|
|
if (OutputBufferLength < sizeof(QOS))
|
|
{
|
|
*NumberOfBytesReturned = MAX_ATM_OPTIONS_LENGTH;
|
|
err = WSAEFAULT;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Request the Winsock DLL to get the options.
|
|
//
|
|
BytesReturned = OutputBufferLength;
|
|
err = getsockopt(
|
|
SocketHandle,
|
|
SOL_SOCKET,
|
|
SO_CONNOPT,
|
|
OutputBuffer,
|
|
&BytesReturned
|
|
);
|
|
|
|
if ((err == NO_ERROR) && (BytesReturned != 0))
|
|
{
|
|
*NumberOfBytesReturned = BytesReturned;
|
|
|
|
lpQOS = (LPQOS)OutputBuffer;
|
|
|
|
//
|
|
// Fix up the provider-specific part, if any.
|
|
//
|
|
if (BytesReturned > sizeof(QOS))
|
|
{
|
|
lpQOS->ProviderSpecific.buf = (PCHAR)((PCHAR)lpQOS + sizeof(QOS));
|
|
}
|
|
else
|
|
{
|
|
lpQOS->ProviderSpecific.buf = NULL;
|
|
lpQOS->ProviderSpecific.len = 0;
|
|
}
|
|
DBGPRINT(("GetQoS: lpQOS %x, ProvSpec buf %x, len %d\n",
|
|
lpQOS, lpQOS->ProviderSpecific.buf, lpQOS->ProviderSpecific.len));
|
|
}
|
|
else
|
|
{
|
|
if (BytesReturned == 0)
|
|
{
|
|
//
|
|
// Probably because we aren't connected yet? Let's return
|
|
// all "NOT_SPECIFIED" values:
|
|
//
|
|
*NumberOfBytesReturned = sizeof(QOS);
|
|
|
|
lpQOS = (LPQOS)OutputBuffer;
|
|
lpQOS->ProviderSpecific.buf = NULL;
|
|
lpQOS->ProviderSpecific.len = 0;
|
|
|
|
lpQOS->SendingFlowspec.TokenRate =
|
|
lpQOS->SendingFlowspec.TokenBucketSize =
|
|
lpQOS->SendingFlowspec.PeakBandwidth =
|
|
lpQOS->SendingFlowspec.Latency =
|
|
lpQOS->SendingFlowspec.DelayVariation =
|
|
lpQOS->SendingFlowspec.ServiceType =
|
|
lpQOS->SendingFlowspec.MaxSduSize =
|
|
lpQOS->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
|
|
lpQOS->ReceivingFlowspec = lpQOS->SendingFlowspec;
|
|
|
|
} else {
|
|
|
|
err = WSAGetLastError();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
INT
|
|
AtmAssociatePVC(
|
|
IN SOCKET SocketHandle,
|
|
IN PVOID HelperDllSocketContext,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength
|
|
)
|
|
{
|
|
INT err;
|
|
PWSHATM_SOCKET_CONTEXT context;
|
|
ATM_PVC_PARAMS * pInPvcParams;
|
|
|
|
context = (PWSHATM_SOCKET_CONTEXT)HelperDllSocketContext;
|
|
|
|
DBGPRINT(("AssociatePVC: InputBuffer %x, Length %d, sizeof(ATM_PVC_PARAMS) %d\n",
|
|
InputBuffer, InputBufferLength, sizeof(ATM_PVC_PARAMS)));
|
|
|
|
do {
|
|
|
|
if ( InputBuffer == NULL ||
|
|
InputBufferLength < sizeof(ATM_PVC_PARAMS) ) {
|
|
|
|
err = WSAEFAULT;
|
|
break;
|
|
}
|
|
|
|
if ( context == NULL ) {
|
|
|
|
err = WSAEINVAL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We want to allow the user to change the PVC info any number of times
|
|
// before connecting, but not after the fact.
|
|
//
|
|
if ( TdiConnectionObjectHandle != NULL ) {
|
|
|
|
err = WSAEISCONN;
|
|
break;
|
|
}
|
|
|
|
if ( context->LocalFlags & WSHATM_SOCK_IS_PVC ) {
|
|
//
|
|
// Already associated. Fail this.
|
|
//
|
|
|
|
err = WSAEISCONN;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Use the standard QoS mechanism to associate the QOS info
|
|
// with this socket.
|
|
//
|
|
pInPvcParams = InputBuffer;
|
|
|
|
err = setsockopt(
|
|
SocketHandle,
|
|
SOL_SOCKET,
|
|
SO_CONNOPT,
|
|
(PCHAR)&pInPvcParams->PvcQos,
|
|
InputBufferLength - (DWORD)((PUCHAR)&pInPvcParams->PvcQos - (PUCHAR)pInPvcParams)
|
|
);
|
|
|
|
|
|
DBGPRINT(("AssociatePVC: setsockopt, ptr %x, length %d, ret %d\n",
|
|
&pInPvcParams->PvcQos,
|
|
InputBufferLength - (DWORD)((PUCHAR)&pInPvcParams->PvcQos - (PUCHAR)pInPvcParams),
|
|
err));
|
|
|
|
if ( err != NO_ERROR ) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Store the Connection Id.
|
|
//
|
|
context->ConnectionId = pInPvcParams->PvcConnectionId;
|
|
context->LocalFlags |= WSHATM_SOCK_IS_PVC;
|
|
|
|
if ( TdiAddressObjectHandle == NULL ) {
|
|
|
|
//
|
|
// We've got an ASSOCIATE_PVC before this socket has been
|
|
// bound. Just remember this, so that we do the rest when
|
|
// the bind actually happens.
|
|
//
|
|
context->LocalFlags |= WSHATM_SOCK_ASSOCIATE_PVC_PENDING;
|
|
err = NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The socket is bound, so send info about the PVC Connection
|
|
// ID to the transport.
|
|
//
|
|
err = AtmDoAssociatePVC(
|
|
context,
|
|
TdiAddressObjectHandle
|
|
);
|
|
DBGPRINT(("AssociatePVC: DoAssociatePVC ret %d\n", err));
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
DBGPRINT(("AssociatePVC: context Flags %x, LocalFlags %x, returning %d\n",
|
|
context? context->Flags: 0,
|
|
context? context->LocalFlags: 0,
|
|
err));
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
INT
|
|
AtmDoAssociatePVC(
|
|
IN PWSHATM_SOCKET_CONTEXT Context,
|
|
IN HANDLE TdiAddressObjectHandle
|
|
)
|
|
{
|
|
INT err;
|
|
|
|
DBGPRINT(("DoAssociatePVC: Context %x, LocalFlags %x\n",
|
|
Context, LocalFlags));
|
|
|
|
Context->LocalFlags &= ~WSHATM_SOCK_ASSOCIATE_PVC_PENDING;
|
|
|
|
err = AtmSetAtmObjectInformation(
|
|
TdiAddressObjectHandle,
|
|
IOCTL_RWAN_MEDIA_SPECIFIC_ADDR_HANDLE_SET,
|
|
ATMSP_OID_PVC_ID,
|
|
&Context->ConnectionId,
|
|
sizeof(ATM_CONNECTION_ID)
|
|
);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
INT
|
|
AtmQueryAtmGlobalInformation(
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN LPVOID pContext,
|
|
IN DWORD ContextLength,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
)
|
|
{
|
|
INT err;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
UNICODE_STRING deviceName;
|
|
HANDLE deviceHandle = NULL;
|
|
PIO_STATUS_BLOCK ioStatusBlock;
|
|
PATM_QUERY_INFORMATION_EX pQueryInfo;
|
|
|
|
do
|
|
{
|
|
ioStatusBlock = RTL_ALLOCATE_HEAP(
|
|
RtlProcessHeap( ),
|
|
0,
|
|
sizeof(*ioStatusBlock) + sizeof(ATM_QUERY_INFORMATION_EX) + ContextLength
|
|
);
|
|
|
|
if ( ioStatusBlock == NULL ) {
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Open a handle to the ATM device.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&deviceName,
|
|
DD_ATM_DEVICE_NAME
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&deviceName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
&deviceHandle,
|
|
SYNCHRONIZE | GENERIC_EXECUTE,
|
|
&objectAttributes,
|
|
ioStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pQueryInfo = (PATM_QUERY_INFORMATION_EX)(ioStatusBlock + 1);
|
|
pQueryInfo->ObjectId = ObjectId;
|
|
pQueryInfo->ContextLength = ContextLength;
|
|
|
|
if ( pQueryInfo->ContextLength > 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
pQueryInfo->Context,
|
|
pContext,
|
|
pQueryInfo->ContextLength
|
|
);
|
|
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
deviceHandle,
|
|
NULL, // No Event
|
|
NULL, // No completion APC
|
|
NULL, // No completion APC Context
|
|
ioStatusBlock,
|
|
IOCTL_RWAN_MEDIA_SPECIFIC_GLOBAL_QUERY,
|
|
pQueryInfo,
|
|
sizeof(ATM_QUERY_INFORMATION_EX) + ContextLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
DBGPRINT(("DevIoControl (Oid %x) returned x%x, Info %d\n",
|
|
pQueryInfo->ObjectId, status, ioStatusBlock->Information));
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
err = NO_ERROR;
|
|
*NumberOfBytesReturned = (ULONG)ioStatusBlock->Information;
|
|
}
|
|
else {
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if( deviceHandle != NULL ) {
|
|
|
|
NtClose( deviceHandle );
|
|
|
|
}
|
|
|
|
if ( ioStatusBlock != NULL ) {
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, ioStatusBlock );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
INT
|
|
AtmSetGenericObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN RWAN_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a RWAN Set Information action to the Raw Wan driver. This operation
|
|
is directed to either an Address Object or to a Connection object, according
|
|
to TdiObjectHandle.
|
|
|
|
Arguments:
|
|
|
|
TdiObjectHandle - a TDI handle to either an Address or a Connection object
|
|
on which to perform the Set Info operation.
|
|
|
|
IoControlCode - IOCTL_RWAN_GENERIC_XXXSET
|
|
|
|
ObjectId - value to put in the ObjectId field of the Set Info structure.
|
|
|
|
InputBuffer - Points to buffer containing value for the Object.
|
|
|
|
InputBufferLength - Length of the above.
|
|
|
|
Return Value:
|
|
|
|
INT - NO_ERROR, or a Windows Sockets error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
INT err;
|
|
PRWAN_SET_INFORMATION_EX pSetInfo;
|
|
PIO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
do
|
|
{
|
|
ioStatusBlock = RTL_ALLOCATE_HEAP(
|
|
RtlProcessHeap( ),
|
|
0,
|
|
sizeof(*ioStatusBlock) + sizeof(RWAN_SET_INFORMATION_EX) + InputBufferLength
|
|
);
|
|
|
|
if ( ioStatusBlock == NULL ) {
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
pSetInfo = (PRWAN_SET_INFORMATION_EX)(ioStatusBlock + 1);
|
|
pSetInfo->ObjectId = ObjectId;
|
|
pSetInfo->BufferSize = InputBufferLength;
|
|
|
|
if ( pSetInfo->BufferSize > 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
pSetInfo->Buffer,
|
|
InputBuffer,
|
|
pSetInfo->BufferSize
|
|
);
|
|
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiObjectHandle,
|
|
NULL, // No Event
|
|
NULL, // No completion APC
|
|
NULL, // No completion APC Context
|
|
ioStatusBlock,
|
|
IoControlCode,
|
|
pSetInfo,
|
|
sizeof(RWAN_SET_INFORMATION_EX) + InputBufferLength,
|
|
NULL, // No output buffer
|
|
0 // output buffer length
|
|
);
|
|
|
|
DBGPRINT(("AtmSetInfo: IOCTL (Oid %x) returned x%x\n", pSetInfo->ObjectId, status));
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
err = NO_ERROR;
|
|
}
|
|
else {
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if ( ioStatusBlock != NULL ) {
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, ioStatusBlock );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
INT
|
|
AtmGetGenericObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN RWAN_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a RWAN Get Information action to the Raw Wan driver. This operation
|
|
is directed to either an Address Object or to a Connection object, according
|
|
to TdiObjectHandle.
|
|
|
|
Arguments:
|
|
|
|
TdiObjectHandle - a TDI handle to either an Address or a Connection object
|
|
on which to perform the Set Info operation.
|
|
|
|
IoControlCode - IOCTL_RWAN_GENERIC_XXXGET
|
|
|
|
ObjectId - value to put in the ObjectId field of the Set Info structure.
|
|
|
|
InputBuffer - Points to buffer containing context for the Object.
|
|
|
|
InputBufferLength - Length of the above.
|
|
|
|
OutputBuffer - place to return value
|
|
|
|
OutputBufferLength - bytes available in OutputBuffer
|
|
|
|
NumberOfBytesReturned - place to return bytes written
|
|
|
|
Return Value:
|
|
|
|
INT - NO_ERROR, or a Windows Sockets error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
INT err;
|
|
PRWAN_QUERY_INFORMATION_EX pQueryInfo;
|
|
PIO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
do
|
|
{
|
|
ioStatusBlock = RTL_ALLOCATE_HEAP(
|
|
RtlProcessHeap( ),
|
|
0,
|
|
sizeof(*ioStatusBlock) + sizeof(RWAN_QUERY_INFORMATION_EX) + InputBufferLength
|
|
);
|
|
|
|
if ( ioStatusBlock == NULL ) {
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
pQueryInfo = (PRWAN_QUERY_INFORMATION_EX)(ioStatusBlock + 1);
|
|
pQueryInfo->ObjectId = ObjectId;
|
|
pQueryInfo->ContextLength = InputBufferLength;
|
|
|
|
if ( pQueryInfo->ContextLength > 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
pQueryInfo->Context,
|
|
InputBuffer,
|
|
pQueryInfo->ContextLength
|
|
);
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiObjectHandle,
|
|
NULL, // No Event
|
|
NULL, // No completion APC
|
|
NULL, // No completion APC Context
|
|
ioStatusBlock,
|
|
IoControlCode,
|
|
pQueryInfo,
|
|
sizeof(RWAN_QUERY_INFORMATION_EX) + InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength // output buffer length
|
|
);
|
|
|
|
DBGPRINT(("AtmGetGenericInfo: IOCTL (Oid %x) returned x%x\n", pQueryInfo->ObjectId, status));
|
|
if ( NT_SUCCESS(status) ) {
|
|
err = NO_ERROR;
|
|
*NumberOfBytesReturned = (ULONG)ioStatusBlock->Information;
|
|
}
|
|
else {
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if ( ioStatusBlock != NULL ) {
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, ioStatusBlock );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
AtmSetAtmObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a Media-specific Set Information action to the Raw Wan driver.
|
|
This operation is directed to either an Address Object or to a Connection
|
|
object, according to TdiObjectHandle.
|
|
|
|
Arguments:
|
|
|
|
TdiObjectHandle - a TDI handle to either an Address or a Connection object
|
|
on which to perform the Set Info operation.
|
|
|
|
IoControlCode - IOCTL_RWAN_MEDIA_SPECIFIC_XXX
|
|
|
|
ObjectId - value to put in the ObjectId field of the Set Info structure.
|
|
|
|
InputBuffer - Points to buffer containing value for the Object.
|
|
|
|
InputBufferLength - Length of the above.
|
|
|
|
Return Value:
|
|
|
|
INT - NO_ERROR, or a Windows Sockets error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
INT err;
|
|
PATM_SET_INFORMATION_EX pSetInfo;
|
|
PIO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
do
|
|
{
|
|
ioStatusBlock = RTL_ALLOCATE_HEAP(
|
|
RtlProcessHeap( ),
|
|
0,
|
|
sizeof(*ioStatusBlock) + sizeof(ATM_SET_INFORMATION_EX) + InputBufferLength
|
|
);
|
|
|
|
if ( ioStatusBlock == NULL ) {
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
pSetInfo = (PATM_SET_INFORMATION_EX)(ioStatusBlock + 1);
|
|
pSetInfo->ObjectId = ObjectId;
|
|
pSetInfo->BufferSize = InputBufferLength;
|
|
|
|
if ( pSetInfo->BufferSize > 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
pSetInfo->Buffer,
|
|
InputBuffer,
|
|
pSetInfo->BufferSize
|
|
);
|
|
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiObjectHandle,
|
|
NULL, // No Event
|
|
NULL, // No completion APC
|
|
NULL, // No completion APC Context
|
|
ioStatusBlock,
|
|
IoControlCode,
|
|
pSetInfo,
|
|
sizeof(ATM_SET_INFORMATION_EX) + InputBufferLength,
|
|
NULL, // No output buffer
|
|
0 // output buffer length
|
|
);
|
|
|
|
DBGPRINT(("AtmSetInfo: IOCTL (Oid %x) returned x%x\n", pSetInfo->ObjectId, status));
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
err = NO_ERROR;
|
|
}
|
|
else {
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if ( ioStatusBlock != NULL ) {
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, ioStatusBlock );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
INT
|
|
AtmGetAtmObjectInformation (
|
|
IN HANDLE TdiObjectHandle,
|
|
IN ULONG IoControlCode,
|
|
IN ATM_OBJECT_ID ObjectId,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a Media-specific Get Information action to the Raw Wan driver.
|
|
This operation is directed to either an Address Object or to a Connection
|
|
object, according to TdiObjectHandle.
|
|
|
|
Arguments:
|
|
|
|
TdiObjectHandle - a TDI handle to either an Address or a Connection object
|
|
on which to perform the Set Info operation.
|
|
|
|
IoControlCode - IOCTL_RWAN_MEDIA_SPECIFIC_XXX
|
|
|
|
ObjectId - value to put in the ObjectId field of the Set Info structure.
|
|
|
|
InputBuffer - Points to buffer containing context for the Object.
|
|
|
|
InputBufferLength - Length of the above.
|
|
|
|
OutputBuffer - place to return value
|
|
|
|
OutputBufferLength - bytes available in OutputBuffer
|
|
|
|
NumberOfBytesReturned - place to return bytes written
|
|
|
|
Return Value:
|
|
|
|
INT - NO_ERROR, or a Windows Sockets error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
INT err;
|
|
PATM_QUERY_INFORMATION_EX pQueryInfo;
|
|
PIO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
do
|
|
{
|
|
|
|
*NumberOfBytesReturned = 0;
|
|
|
|
ioStatusBlock = RTL_ALLOCATE_HEAP(
|
|
RtlProcessHeap( ),
|
|
0,
|
|
sizeof(*ioStatusBlock) + sizeof(ATM_QUERY_INFORMATION_EX) + InputBufferLength
|
|
);
|
|
|
|
if ( ioStatusBlock == NULL ) {
|
|
err = WSAENOBUFS;
|
|
break;
|
|
}
|
|
|
|
pQueryInfo = (PATM_QUERY_INFORMATION_EX)(ioStatusBlock + 1);
|
|
pQueryInfo->ObjectId = ObjectId;
|
|
pQueryInfo->ContextLength = InputBufferLength;
|
|
|
|
if ( pQueryInfo->ContextLength > 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
pQueryInfo->Context,
|
|
InputBuffer,
|
|
pQueryInfo->ContextLength
|
|
);
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiObjectHandle,
|
|
NULL, // No Event
|
|
NULL, // No completion APC
|
|
NULL, // No completion APC Context
|
|
ioStatusBlock,
|
|
IoControlCode,
|
|
pQueryInfo,
|
|
sizeof(ATM_QUERY_INFORMATION_EX) + InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
DBGPRINT(("AtmGetAtmObjInfo: IOCTL (Oid %x) returned x%x\n",
|
|
pQueryInfo->ObjectId, status));
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
err = NO_ERROR;
|
|
*NumberOfBytesReturned = (ULONG)ioStatusBlock->Information;
|
|
}
|
|
else {
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
err = WSAEFAULT;
|
|
} else {
|
|
err = WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if ( ioStatusBlock != NULL ) {
|
|
RTL_FREE_HEAP( RtlProcessHeap( ), 0, ioStatusBlock );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#if DBG
|
|
PVOID
|
|
MyRtlAllocateHeap(
|
|
IN PVOID HeapHandle,
|
|
IN ULONG Flags,
|
|
IN ULONG Size,
|
|
IN ULONG LineNumber
|
|
)
|
|
{
|
|
PVOID pRetValue;
|
|
|
|
pRetValue = RtlAllocateHeap(HeapHandle, Flags, Size);
|
|
|
|
#if DBG2
|
|
DbgPrint("WSHATM: AllocHeap size %d at line %d, ret x%x\n",
|
|
Size, LineNumber, pRetValue);
|
|
#endif
|
|
return (pRetValue);
|
|
}
|
|
|
|
|
|
VOID
|
|
MyRtlFreeHeap(
|
|
IN PVOID HeapHandle,
|
|
IN ULONG Flags,
|
|
IN PVOID MemPtr,
|
|
IN ULONG LineNumber
|
|
)
|
|
{
|
|
#if DBG2
|
|
DbgPrint("WSHATM: FreeHeap x%x, line %d\n", MemPtr, LineNumber);
|
|
#endif
|
|
RtlFreeHeap(HeapHandle, Flags, MemPtr);
|
|
}
|
|
|
|
#endif // DBG
|