Source code of Windows XP (NT5)
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.

1897 lines
48 KiB

  1. /****************************************************************************
  2. * (c) Copyright 1993 Micro Computer Systems, Inc. All rights reserved.
  3. *****************************************************************************
  4. *
  5. * Title: IPX WinSock Helper DLL for Windows NT
  6. *
  7. * Module: ipx/sockhelp/wshelper.c
  8. *
  9. * Version: 1.00.00
  10. *
  11. * Date: 04-08-93
  12. *
  13. * Author: Brian Walker
  14. *
  15. *****************************************************************************
  16. *
  17. * Change Log:
  18. *
  19. * Date DevSFC Comment
  20. * -------- ------ -------------------------------------------------------
  21. *
  22. *****************************************************************************
  23. *
  24. * Functional Description:
  25. *
  26. ****************************************************************************/
  27. #include <nt.h>
  28. #include <ntrtl.h>
  29. #include <nturtl.h>
  30. #include <windef.h>
  31. #include <winbase.h>
  32. #include <tdi.h>
  33. #include <winsock2.h>
  34. #include <wsahelp.h>
  35. #include <basetyps.h>
  36. #include <nspapi.h>
  37. #include <nspapip.h>
  38. #include <wsipx.h>
  39. #include <wsnwlink.h>
  40. #include <isnkrnl.h>
  41. #include <stdio.h>
  42. #if defined(UNICODE)
  43. #define NWLNKSPX_SERVICE_NAME L"nwlnkspx"
  44. #else
  45. #define NWLNKSPX_SERVICE_NAME "nwlnkspx"
  46. #endif
  47. typedef struct _IPX_OLD_ADDRESS_DATA {
  48. UINT adapternum;
  49. UCHAR netnum[4];
  50. UCHAR nodenum[6];
  51. } IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
  52. /** Device names for IPX sockets **/
  53. #define ISNDGRAM_DEVNAME L"\\Device\\NwlnkIpx"
  54. /** Device names for SPX/SPXII sockets **/
  55. #define ISNSTREAM_DEVNAME L"\\Device\\NwlnkSpx\\SpxStream"
  56. #define ISNSEQPKT_DEVNAME L"\\Device\\NwlnkSpx\\Spx"
  57. #define ISNSTREAMII_DEVNAME L"\\Device\\NwlnkSpx\\Stream"
  58. #define ISNSEQPKTII_DEVNAME L"\\Device\\NwlnkSpx"
  59. /** Friendly names for IPX and SPX. **/
  60. #define SPX_NAME L"SPX"
  61. #define SPX2_NAME L"SPX II"
  62. #define IPX_NAME L"IPX"
  63. /** Start for IPX protocol families **/
  64. #define MCSBASE_DGRAM NSPROTO_IPX
  65. #define BUFFER_SIZE 40
  66. /** **/
  67. UCHAR wsh_bcast[6] = {
  68. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  69. };
  70. // SPX Loaded flag, set for each process
  71. BOOLEAN SpxLoaded = FALSE;
  72. //
  73. // IPX/SPX provider GUIDs.
  74. //
  75. GUID IpxProviderGuid =
  76. { /* 11058240-be47-11cf-95c8-00805f48a192 */
  77. 0x11058240,
  78. 0xbe47,
  79. 0x11cf,
  80. { 0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
  81. };
  82. GUID SpxProviderGuid =
  83. { /* 11058241-be47-11cf-95c8-00805f48a192 */
  84. 0x11058241,
  85. 0xbe47,
  86. 0x11cf,
  87. { 0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
  88. };
  89. /** Forward Decls/External Prototypes **/
  90. DWORD
  91. WshLoadSpx(
  92. VOID);
  93. extern
  94. INT
  95. do_tdi_action(
  96. HANDLE,
  97. ULONG,
  98. PUCHAR,
  99. INT,
  100. BOOLEAN,
  101. PHANDLE OPTIONAL);
  102. /*page****************************************************************
  103. These are the triples we support.
  104. *********************************************************************/
  105. typedef struct _MAPPING_TRIPLE {
  106. INT triple_addrfam;
  107. INT triple_socktype;
  108. INT triple_protocol;
  109. } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
  110. #define MAPPING_NUM_COLUMNS 3
  111. extern MAPPING_TRIPLE stream_triples[];
  112. extern int stream_num_triples;
  113. extern int stream_table_size;
  114. extern MAPPING_TRIPLE dgram_triples[];
  115. extern int dgram_num_triples;
  116. extern int dgram_table_size;
  117. /** Forward declarations on internal routines **/
  118. BOOLEAN is_triple_in_list(PMAPPING_TRIPLE, ULONG, INT, INT, INT);
  119. /**
  120. There is one of these structures allocated for every
  121. socket that is created for us.
  122. **/
  123. typedef struct _WSHIPX_SOCKET_CONTEXT {
  124. INT con_addrfam;
  125. INT con_socktype;
  126. INT con_pcol;
  127. INT con_flags;
  128. UCHAR con_sendptype; /* Current send packet type */
  129. UCHAR con_recvptype; /* Recv ptype we are filtering on */
  130. UCHAR con_dstype; /* Datastream type */
  131. } WSHIPX_SOCKET_CONTEXT, *PWSHIPX_SOCKET_CONTEXT;
  132. /** Values for con_flags **/
  133. #define WSHCON_FILTER 0x0001 /* We are filtering on recv pkt type */
  134. #define WSHCON_EXTADDR 0x0002 /* Extended addressing is on */
  135. #define WSHCON_SENDHDR 0x0004 /* Send header flag */
  136. #define WSHCON_RCVBCAST 0x0008 /* It does receive broadcasts */
  137. #define WSHCON_IMM_SPXACK 0x0020 /* Immediate spx acks no piggyback */
  138. /*page***************************************************************
  139. W S H O p e n S o c k e t
  140. This is called for the socket call. We make sure that
  141. we support the address family/socket type/protocol triple
  142. given and then we will allocate some memory to keep track
  143. of the socket.
  144. Arguments - addrfam = Entry: Address family from socket call
  145. Exit: Filled in address family
  146. socktype = Entry: Socket type from socket call
  147. Exit: Filled in socket type
  148. pcol = Entry: Protocol from socket call
  149. Exit: Filled in protocol
  150. devname = Ptr to where to store device name
  151. pcontext = Where to store context value
  152. events = Bitmask for events we want to know about
  153. Returns - NO_ERROR = OK
  154. Else = WinSock Error Code
  155. *********************************************************************/
  156. INT WSHOpenSocket(PINT addrfam, PINT socktype, PINT pcol,
  157. PUNICODE_STRING devname, PVOID *pcontext, PDWORD events)
  158. {
  159. PWSHIPX_SOCKET_CONTEXT context;
  160. /** Determine whether this is DGRAM or STREAM or SEQPACKET **/
  161. if (is_triple_in_list(stream_triples, stream_num_triples,
  162. *addrfam, *socktype, *pcol)) {
  163. if (*socktype == SOCK_SEQPACKET) {
  164. if (*pcol == NSPROTO_SPX)
  165. RtlInitUnicodeString(devname, ISNSEQPKT_DEVNAME);
  166. else
  167. RtlInitUnicodeString(devname, ISNSEQPKTII_DEVNAME);
  168. }
  169. else {
  170. if (*pcol == NSPROTO_SPX)
  171. RtlInitUnicodeString(devname, ISNSTREAM_DEVNAME);
  172. else
  173. RtlInitUnicodeString(devname, ISNSTREAMII_DEVNAME);
  174. }
  175. if (!SpxLoaded) {
  176. WshLoadSpx();
  177. }
  178. }
  179. /** Check for DGRAM **/
  180. else if (is_triple_in_list(dgram_triples, dgram_num_triples,
  181. *addrfam, *socktype, *pcol)) {
  182. RtlInitUnicodeString(devname, ISNDGRAM_DEVNAME);
  183. }
  184. /**
  185. All others are errors. This should never happen unless
  186. the registry information is wrong.
  187. **/
  188. else
  189. return WSAEINVAL;
  190. /** Allocate context for the socket **/
  191. context = RtlAllocateHeap(RtlProcessHeap(), 0L, sizeof(*context));
  192. if (context == NULL)
  193. return WSAENOBUFS;
  194. /** Init the context **/
  195. context->con_addrfam = *addrfam;
  196. context->con_socktype = *socktype;
  197. context->con_pcol = *pcol;
  198. context->con_flags = WSHCON_RCVBCAST;
  199. context->con_sendptype = (UCHAR)(*pcol - MCSBASE_DGRAM);
  200. context->con_recvptype = 0;
  201. context->con_dstype = 0;
  202. /**
  203. Tell the Windows Sockets DLL which state transitions we
  204. are interested in.
  205. **/
  206. *events = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND | WSH_NOTIFY_CONNECT;
  207. /** Give WinSock DLL our context pointer **/
  208. *pcontext = context;
  209. /** Everything OK - return OK **/
  210. return NO_ERROR;
  211. }
  212. /*page**************************************************************
  213. W S H G e t S o c k A d d r T y p e
  214. This routine parses a sockaddr to determine the type
  215. of machine address and endpoint address portions of the
  216. sockaddr. This is called by the WinSock DLL whenever it
  217. needs to interpret a sockaddr.
  218. Arguments - sockaddr = Ptr to sockaddr struct to evaluate
  219. sockaddrlen = Length of data in the sockaddr
  220. sockaddrinfo = Ptr to structure to recv info
  221. about the sockaddr
  222. Returns - NO_ERROR = Evaluation OK
  223. Else = WinSock error code
  224. ********************************************************************/
  225. INT WSHGetSockaddrType(PSOCKADDR sockaddr, DWORD sockaddrlen,
  226. PSOCKADDR_INFO sockaddrinfo)
  227. {
  228. PSOCKADDR_IPX sa = (PSOCKADDR_IPX)sockaddr;
  229. /** Make sure the address family is correct **/
  230. if (sa->sa_family != AF_NS)
  231. return WSAEAFNOSUPPORT;
  232. /** Make sure the length is OK **/
  233. if (sockaddrlen < sizeof(SOCKADDR_IPX))
  234. return WSAEFAULT;
  235. /** Looks like a good addr - determine the type **/
  236. if (!memcmp(sa->sa_nodenum, wsh_bcast, 6))
  237. sockaddrinfo->AddressInfo = SockaddrAddressInfoBroadcast;
  238. else
  239. sockaddrinfo->AddressInfo = SockaddrAddressInfoNormal;
  240. /** Determine the endpoint **/
  241. if (sa->sa_socket == 0)
  242. sockaddrinfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  243. else if (ntohs(sa->sa_socket) < 2000)
  244. sockaddrinfo->EndpointInfo = SockaddrEndpointInfoReserved;
  245. else
  246. sockaddrinfo->EndpointInfo = SockaddrEndpointInfoNormal;
  247. /** **/
  248. return NO_ERROR;
  249. }
  250. /*page**************************************************************
  251. W S H G e t W i n s o c k M a p p i n g
  252. Returns the list of address family/socket type/protocol
  253. triples supported by this helper DLL.
  254. Arguments - mapping = Contect ptr from WSAOpenSocket
  255. maplen =
  256. Returns - The length in bytes of a eeded OK
  257. Else = WinSock error code
  258. ********************************************************************/
  259. DWORD WSHGetWinsockMapping(PWINSOCK_MAPPING mapping, DWORD maplen)
  260. {
  261. DWORD len;
  262. /**
  263. Figure how much data we are going to copy into
  264. the user buffer.
  265. **/
  266. len = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
  267. dgram_table_size + stream_table_size;
  268. /**
  269. If the buffer passed is too small, then return the size
  270. that is needed. The caller should then call us again
  271. with a buffer of the correct size.
  272. **/
  273. if (len > maplen)
  274. return len;
  275. /** Fill in the output buffer **/
  276. mapping->Rows = stream_num_triples + dgram_num_triples;
  277. mapping->Columns = MAPPING_NUM_COLUMNS;
  278. RtlMoveMemory(mapping->Mapping,
  279. stream_triples,
  280. stream_table_size);
  281. RtlMoveMemory((PCHAR)mapping->Mapping + stream_table_size,
  282. dgram_triples,
  283. dgram_table_size);
  284. /** Return the number of bytes we filled in **/
  285. return len;
  286. }
  287. /*page***************************************************************
  288. W S H N o t i f y
  289. This routine is called for events that we registered at
  290. open socket time.
  291. Arguments - context = Context ptr from WSAOpenSocket
  292. handle = Socket handle
  293. addrhandle = Datagram Handle
  294. connhandle = Connection Handle
  295. event = What event happened
  296. Returns - NO_ERROR = Operation succeeded OK
  297. Else = WinSock error code
  298. *********************************************************************/
  299. INT WSHNotify(PVOID context, SOCKET handle,
  300. HANDLE addrhandle, HANDLE connhandle,
  301. DWORD event)
  302. {
  303. INT rc;
  304. INT t1;
  305. PWSHIPX_SOCKET_CONTEXT ct;
  306. /** Get context pointer **/
  307. ct = (PWSHIPX_SOCKET_CONTEXT)context;
  308. /** On close - just free the context structure **/
  309. if (event == WSH_NOTIFY_CLOSE) {
  310. RtlFreeHeap(RtlProcessHeap(), 0L, context);
  311. return NO_ERROR;
  312. }
  313. /** On bind set the send packet type **/
  314. if (event == WSH_NOTIFY_BIND)
  315. {
  316. if (ct->con_socktype == SOCK_DGRAM)
  317. {
  318. /** Set the send packet ptype **/
  319. t1 = (UINT)ct->con_sendptype;
  320. rc = WSHSetSocketInformation(
  321. context, handle, addrhandle,
  322. connhandle, NSPROTO_IPX,
  323. IPX_PTYPE, (PCHAR)&t1, sizeof(INT));
  324. if (rc)
  325. return rc;
  326. if (ct->con_flags & WSHCON_EXTADDR)
  327. {
  328. t1 = 1;
  329. rc = WSHSetSocketInformation(
  330. context, handle, addrhandle,
  331. connhandle, NSPROTO_IPX,
  332. IPX_EXTENDED_ADDRESS, (PCHAR)&t1, sizeof(INT));
  333. if (rc)
  334. return rc;
  335. }
  336. /** Set the recv filter packet type **/
  337. if (ct->con_flags & WSHCON_FILTER)
  338. {
  339. t1 = (UINT)ct->con_recvptype;
  340. rc = WSHSetSocketInformation(
  341. context, handle, addrhandle,
  342. connhandle, NSPROTO_IPX,
  343. IPX_FILTERPTYPE, (PCHAR)&t1, sizeof(INT));
  344. if (rc)
  345. return rc;
  346. }
  347. /** Set up broadcast reception **/
  348. if (ct->con_flags & WSHCON_RCVBCAST)
  349. {
  350. t1 = 1;
  351. rc = WSHSetSocketInformation(
  352. context, handle, addrhandle,
  353. connhandle, NSPROTO_IPX,
  354. IPX_RECEIVE_BROADCAST, (PCHAR)&t1, sizeof(INT));
  355. if (rc)
  356. return rc;
  357. }
  358. /** Enable send header if we need to **/
  359. if (ct->con_flags & WSHCON_SENDHDR)
  360. {
  361. t1 = 1;
  362. rc = WSHSetSocketInformation(
  363. context, handle, addrhandle,
  364. connhandle, NSPROTO_IPX,
  365. IPX_RECVHDR, (PCHAR)&t1, sizeof(INT));
  366. if (rc)
  367. return rc;
  368. }
  369. }
  370. else if ((ct->con_socktype == SOCK_STREAM) ||
  371. (ct->con_socktype == SOCK_SEQPACKET))
  372. {
  373. if (ct->con_flags & WSHCON_SENDHDR)
  374. {
  375. t1 = 1;
  376. rc = WSHSetSocketInformation(
  377. context, handle, addrhandle,
  378. connhandle, NSPROTO_IPX,
  379. IPX_RECVHDR, (PCHAR)&t1, sizeof(INT));
  380. if (rc)
  381. return rc;
  382. }
  383. if (ct->con_flags & WSHCON_IMM_SPXACK)
  384. {
  385. t1 = 1;
  386. rc = WSHSetSocketInformation(
  387. context, handle, addrhandle,
  388. connhandle, NSPROTO_IPX,
  389. IPX_IMMEDIATESPXACK, (PCHAR)&t1, sizeof(INT));
  390. if (rc)
  391. return rc;
  392. }
  393. }
  394. /** It is OK - return OK **/
  395. return NO_ERROR;
  396. }
  397. /** On connect set things not set already **/
  398. if (event == WSH_NOTIFY_CONNECT)
  399. {
  400. /** If on DGRAM - just return OK **/
  401. if (ct->con_socktype == SOCK_DGRAM)
  402. return NO_ERROR;
  403. /**
  404. If the datastream type has been set - set it
  405. **/
  406. if (ct->con_dstype)
  407. {
  408. rc = do_tdi_action(connhandle, MSPX_SETDATASTREAM, &ct->con_dstype, 1, FALSE, NULL);
  409. if (rc)
  410. return rc;
  411. }
  412. /** It is OK - return OK **/
  413. return NO_ERROR;
  414. }
  415. /** All others are bad **/
  416. return WSAEINVAL;
  417. }
  418. /*page**************************************************************
  419. W S H G e t S o c k I n f o r m a t i o n
  420. This routine retrieves information about a socket for those
  421. socket options supported in this DLL. The options
  422. supported here are SO_KEEPALIVE and SO_DONTROUTE. This
  423. routine is called by the WinSock DLL when a level/option name
  424. combination is passed to getsockopt that the WinSock DLL
  425. does not understand.
  426. Arguments - context = Context ptr from WSAOpenSocket
  427. handle = Socket handle
  428. addrhandle = Datagram Handle
  429. connhandle = Connection Handle
  430. level = Level from getsockopt call
  431. optname = Option name from getsockopt call
  432. optvalue = Option value ptr from getsockopt call
  433. optlength = Option length field from getsockopt call
  434. Returns - NO_ERROR = Operation succeeded OK
  435. Else = WinSock error code
  436. ********************************************************************/
  437. INT WSHGetSocketInformation(PVOID context, SOCKET handle,
  438. HANDLE addrhandle, HANDLE connhandle,
  439. INT level, INT optname, PCHAR optvalue,
  440. PINT optlength)
  441. {
  442. PWSHIPX_SOCKET_CONTEXT ct;
  443. INT rc;
  444. INT ibuf[2];
  445. PIPX_ADDRESS_DATA p;
  446. /** Get ptr to context **/
  447. ct = (PWSHIPX_SOCKET_CONTEXT)context;
  448. //
  449. // Check if this is an internal request for context information.
  450. //
  451. if ( level == SOL_INTERNAL && optname == SO_CONTEXT ) {
  452. //
  453. // The Windows Sockets DLL is requesting context information
  454. // from us. If an output buffer was not supplied, the Windows
  455. // Sockets DLL is just requesting the size of our context
  456. // information.
  457. //
  458. if ( optvalue != NULL ) {
  459. //
  460. // Make sure that the buffer is sufficient to hold all the
  461. // context information.
  462. //
  463. if ( *optlength < sizeof(*ct) ) {
  464. return WSAEFAULT;
  465. }
  466. //
  467. // Copy in the context information.
  468. //
  469. RtlCopyMemory( optvalue, ct, sizeof(*ct) );
  470. }
  471. *optlength = sizeof(*ct);
  472. return NO_ERROR;
  473. }
  474. /** The only level we support is NSPROTO_IPX **/
  475. if (level != NSPROTO_IPX)
  476. return WSAEINVAL;
  477. /** Fill in the result based on the options name **/
  478. switch (optname) {
  479. /** Get the current send packet type **/
  480. case IPX_PTYPE:
  481. /** Make sure the length is OK **/
  482. if (*optlength < sizeof(INT))
  483. return WSAEFAULT;
  484. /** Make sure this is for a DGRAM socket **/
  485. if (ct->con_socktype != SOCK_DGRAM)
  486. return WSAEINVAL;
  487. /** Set the type **/
  488. *(UINT *)optvalue = (UINT)ct->con_sendptype;
  489. *optlength = sizeof(UINT);
  490. break;
  491. /** Get the current recv packet type filter **/
  492. case IPX_FILTERPTYPE:
  493. /** Make sure length is OK **/
  494. if (*optlength < sizeof(INT))
  495. return WSAEFAULT;
  496. /** Make sure this is for a DGRAM socket **/
  497. if (ct->con_socktype != SOCK_DGRAM)
  498. return WSAEINVAL;
  499. /** If option not on - return error **/
  500. if (!(ct->con_flags & WSHCON_FILTER))
  501. return WSAEINVAL;
  502. /** Save the new value **/
  503. *(UINT *)optvalue = (UINT)ct->con_recvptype;
  504. *optlength = sizeof(UINT);
  505. break;
  506. /** Get the max DGRAM size that can be sent **/
  507. case IPX_MAXSIZE:
  508. /** Make sure length is OK **/
  509. if (*optlength < sizeof(INT))
  510. return WSAEFAULT;
  511. /** Make sure this is for a DGRAM socket **/
  512. if (ct->con_socktype != SOCK_DGRAM)
  513. return WSAEINVAL;
  514. /** Get the value from the driver **/
  515. rc = do_tdi_action(addrhandle, MIPX_GETPKTSIZE, (PUCHAR)ibuf, sizeof(INT)*2, TRUE, NULL);
  516. *(INT *)optvalue = ibuf[1];
  517. *optlength = sizeof(int);
  518. /** Return the result **/
  519. return rc;
  520. /** Get the max adapternum that is valid **/
  521. case IPX_MAX_ADAPTER_NUM:
  522. /** Make sure length is OK **/
  523. if (*optlength < sizeof(INT))
  524. return WSAEFAULT;
  525. /** Make sure this is for a DGRAM socket **/
  526. if (ct->con_socktype != SOCK_DGRAM)
  527. return WSAEINVAL;
  528. /** Get the value from the driver **/
  529. rc = do_tdi_action(addrhandle, MIPX_ADAPTERNUM, optvalue, sizeof(INT), TRUE, NULL);
  530. *optlength = sizeof(int);
  531. /** Return the result **/
  532. return rc;
  533. /** Get SPX statistics **/
  534. case IPX_SPXGETCONNECTIONSTATUS:
  535. /** Make sure data length OK **/
  536. if (*optlength < sizeof(IPX_SPXCONNSTATUS_DATA))
  537. return WSAEFAULT;
  538. /** Make sure this is for a STREAM socket **/
  539. if ((ct->con_socktype != SOCK_STREAM) &&
  540. (ct->con_socktype != SOCK_SEQPACKET)) {
  541. return WSAEINVAL;
  542. }
  543. /** Send it to the driver **/
  544. rc = do_tdi_action(
  545. connhandle,
  546. MSPX_GETSTATS,
  547. optvalue,
  548. *optlength,
  549. FALSE,
  550. NULL);
  551. if (rc)
  552. return rc;
  553. *optlength = sizeof(IPX_SPXCONNSTATUS_DATA);
  554. /** Return OK **/
  555. return NO_ERROR;
  556. /** Get the current datastream type to send pkts with **/
  557. case IPX_DSTYPE:
  558. /** Make sure length is OK **/
  559. if (*optlength < sizeof(INT))
  560. return WSAEFAULT;
  561. /** Make sure this is for a STREAM socket **/
  562. if ((ct->con_socktype != SOCK_STREAM) &&
  563. (ct->con_socktype != SOCK_SEQPACKET)) {
  564. return WSAEINVAL;
  565. }
  566. /** Save the new value **/
  567. *(UINT *)optvalue = (UINT)ct->con_dstype;
  568. *optlength = sizeof(UINT);
  569. break;
  570. /** Get net information **/
  571. case IPX_GETNETINFO:
  572. /** Make sure data length OK **/
  573. if (*optlength < sizeof(IPX_NETNUM_DATA))
  574. return WSAEFAULT;
  575. /** Make sure this is for a DGRAM socket **/
  576. if (ct->con_socktype != SOCK_DGRAM)
  577. return WSAEINVAL;
  578. /** Send it to the driver **/
  579. rc = do_tdi_action(
  580. addrhandle,
  581. MIPX_GETNETINFO,
  582. optvalue,
  583. *optlength,
  584. TRUE,
  585. NULL);
  586. if (rc) {
  587. return rc;
  588. }
  589. *optlength = sizeof(IPX_NETNUM_DATA);
  590. /** Return OK **/
  591. return NO_ERROR;
  592. /** Get net information without RIPping **/
  593. case IPX_GETNETINFO_NORIP:
  594. /** Make sure data length OK **/
  595. if (*optlength < sizeof(IPX_NETNUM_DATA))
  596. return WSAEFAULT;
  597. /** Make sure this is for a DGRAM socket **/
  598. if (ct->con_socktype != SOCK_DGRAM)
  599. return WSAEINVAL;
  600. /** Send it to the driver **/
  601. rc = do_tdi_action(
  602. addrhandle,
  603. MIPX_GETNETINFO_NR,
  604. optvalue,
  605. *optlength,
  606. TRUE,
  607. NULL);
  608. if (rc) {
  609. return rc;
  610. }
  611. *optlength = sizeof(IPX_NETNUM_DATA);
  612. /** Return OK **/
  613. return NO_ERROR;
  614. /** Like GETNETINFO, but force a re-rip **/
  615. case IPX_RERIPNETNUMBER:
  616. /** Make sure data length OK **/
  617. if (*optlength < sizeof(IPX_NETNUM_DATA))
  618. return WSAEFAULT;
  619. /** Make sure this is for a DGRAM socket **/
  620. if (ct->con_socktype != SOCK_DGRAM)
  621. return WSAEINVAL;
  622. /** Send it to the driver **/
  623. rc = do_tdi_action(
  624. addrhandle,
  625. MIPX_RERIPNETNUM,
  626. optvalue,
  627. *optlength,
  628. TRUE,
  629. NULL);
  630. if (rc) {
  631. return rc;
  632. }
  633. *optlength = sizeof(IPX_NETNUM_DATA);
  634. /** Return OK **/
  635. return NO_ERROR;
  636. /** Get card information **/
  637. case IPX_ADDRESS_NOTIFY:
  638. /** We need the action header, the data, and the event handle **/
  639. if (*optlength < (INT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_ADDRESS_DATA) + sizeof(HANDLE)))
  640. return WSAEFAULT;
  641. /** Otherwise just fall through **/
  642. case IPX_ADDRESS:
  643. /** Make sure data length OK **/
  644. if (*optlength < sizeof(IPX_OLD_ADDRESS_DATA))
  645. return WSAEFAULT;
  646. /** Make sure this is for a DGRAM socket **/
  647. if (ct->con_socktype != SOCK_DGRAM)
  648. return WSAEINVAL;
  649. /** Send it to the driver **/
  650. if (optname == IPX_ADDRESS) {
  651. rc = do_tdi_action(
  652. addrhandle,
  653. MIPX_GETCARDINFO,
  654. optvalue,
  655. *optlength,
  656. TRUE,
  657. NULL);
  658. } else {
  659. rc = do_tdi_action(
  660. addrhandle,
  661. MIPX_NOTIFYCARDINFO,
  662. optvalue,
  663. *optlength - sizeof(HANDLE),
  664. TRUE,
  665. (PHANDLE)(optvalue + FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_ADDRESS_DATA)));
  666. }
  667. if (rc) {
  668. p = (PIPX_ADDRESS_DATA)optvalue;
  669. memset(p->netnum, 0xFF, 4);
  670. memset(p->nodenum, 0xFF, 6);
  671. return rc;
  672. }
  673. /** Return OK **/
  674. if (*optlength < sizeof(IPX_ADDRESS_DATA)) {
  675. *optlength = sizeof(IPX_OLD_ADDRESS_DATA);
  676. } else if (*optlength < sizeof(IPX_ADDRESS_DATA)) {
  677. *optlength = sizeof(IPX_ADDRESS_DATA);
  678. }
  679. return NO_ERROR;
  680. /** All others are error **/
  681. default:
  682. return WSAENOPROTOOPT;
  683. }
  684. /** All is OK **/
  685. return NO_ERROR;
  686. }
  687. /*page***************************************************************
  688. W S H S e t S o c k e t I n f o r m a t i o n
  689. This routine sets information about a socket for those
  690. options supported in this helper DLL. This routine
  691. is called when a setsockopt call is made and the option/level
  692. passed is unknown to the WinSock DLL.
  693. Arguments - context = Context ptr from WSAOpenSocket
  694. handle = Socket handle
  695. addrhandle = Datagram Handle
  696. connhandle = Connection Handle
  697. level = Level from getsockopt call
  698. optname = Option name from getsockopt call
  699. optvalue = Option value ptr from getsockopt call
  700. optlength = Option length field from getsockopt call
  701. Returns - NO_ERROR = Operation succeeded OK
  702. Else = WinSock error code
  703. *********************************************************************/
  704. INT WSHSetSocketInformation(PVOID context, SOCKET handle,
  705. HANDLE addrhandle, HANDLE connhandle,
  706. INT level, INT optname, PCHAR optvalue,
  707. INT optlength)
  708. {
  709. PWSHIPX_SOCKET_CONTEXT ct;
  710. INT rc;
  711. /** Get ptr to context **/
  712. ct = (PWSHIPX_SOCKET_CONTEXT)context;
  713. //
  714. // Check if this is an internal request for context information.
  715. //
  716. if ( level == SOL_INTERNAL && optname == SO_CONTEXT ) {
  717. //
  718. // The Windows Sockets DLL is requesting that we set context
  719. // information for a new socket. If the new socket was
  720. // accept()'ed, then we have already been notified of the socket
  721. // and HelperDllSocketContext will be valid. If the new socket
  722. // was inherited or duped into this process, then this is our
  723. // first notification of the socket and HelperDllSocketContext
  724. // will be equal to NULL.
  725. //
  726. // Insure that the context information being passed to us is
  727. // sufficiently large.
  728. //
  729. if ( optlength < sizeof(*ct) ) {
  730. return WSAEINVAL;
  731. }
  732. if ( ct == NULL ) {
  733. //
  734. // This is our notification that a socket handle was
  735. // inherited or duped into this process. Allocate a context
  736. // structure for the new socket.
  737. //
  738. ct = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*ct) );
  739. if ( ct == NULL ) {
  740. return WSAENOBUFS;
  741. }
  742. //
  743. // Copy over information into the context block.
  744. //
  745. RtlCopyMemory( ct, optvalue, sizeof(*ct) );
  746. //
  747. // Tell the Windows Sockets DLL where our context information is
  748. // stored so that it can return the context pointer in future
  749. // calls.
  750. //
  751. *(PWSHIPX_SOCKET_CONTEXT *)optvalue = ct;
  752. return NO_ERROR;
  753. } else {
  754. PWSHIPX_SOCKET_CONTEXT parentContext;
  755. INT one = 1;
  756. //
  757. // The socket was accept()'ed and it needs to have the same
  758. // properties as it's parent. The OptionValue buffer
  759. // contains the context information of this socket's parent.
  760. //
  761. parentContext = (PWSHIPX_SOCKET_CONTEXT)optvalue;
  762. ASSERT( ct->con_addrfam == parentContext->con_addrfam );
  763. ASSERT( ct->con_socktype == parentContext->con_socktype );
  764. ASSERT( ct->con_pcol == parentContext->con_pcol );
  765. return NO_ERROR;
  766. }
  767. }
  768. /** We only support level NSPROTO_IPX **/
  769. if (level != NSPROTO_IPX)
  770. return WSAEINVAL;
  771. /** Handle the options **/
  772. switch (optname) {
  773. /** Set the send packet type **/
  774. case IPX_PTYPE:
  775. /** Make sure length is OK **/
  776. if (optlength < sizeof(INT))
  777. return WSAEFAULT;
  778. /** Make sure this is for a DGRAM socket **/
  779. if (ct->con_socktype != SOCK_DGRAM)
  780. return WSAEINVAL;
  781. /** Get the value and check it **/
  782. rc = *(INT *)optvalue;
  783. if ((rc < 0) || (rc > 255))
  784. return WSAEINVAL;
  785. /** Save the new value **/
  786. ct->con_sendptype = (UCHAR)rc;
  787. /** Send the new value down to the driver **/
  788. if (addrhandle)
  789. rc = do_tdi_action(addrhandle, MIPX_SETSENDPTYPE, &ct->con_sendptype, 1, TRUE, NULL);
  790. else
  791. rc = NO_ERROR;
  792. return rc;
  793. /** Set the recv filter for packet type **/
  794. case IPX_FILTERPTYPE:
  795. /** Make sure length is OK **/
  796. if (optlength < sizeof(INT))
  797. return WSAEFAULT;
  798. /** Make sure this is for a DGRAM socket **/
  799. if (ct->con_socktype != SOCK_DGRAM)
  800. return WSAEINVAL;
  801. /** Get the value and check it **/
  802. rc = *(INT *)optvalue;
  803. if ((rc < 0) || (rc > 255))
  804. return WSAEINVAL;
  805. /** Save the new value **/
  806. ct->con_recvptype = (UCHAR)rc;
  807. ct->con_flags |= WSHCON_FILTER;
  808. /** Send the new value down to the driver **/
  809. if (addrhandle)
  810. rc = do_tdi_action(addrhandle, MIPX_FILTERPTYPE, &ct->con_recvptype, 1, TRUE, NULL);
  811. else
  812. rc = NO_ERROR;
  813. /** **/
  814. return rc;
  815. /** Stop filtering recv on pkt type **/
  816. case IPX_STOPFILTERPTYPE:
  817. /** Make sure this is for a DGRAM socket **/
  818. if (ct->con_socktype != SOCK_DGRAM)
  819. return WSAEINVAL;
  820. /** Turn off the flag **/
  821. ct->con_flags &= ~WSHCON_FILTER;
  822. /** Tell the driver **/
  823. if (addrhandle)
  824. rc = do_tdi_action(addrhandle, MIPX_NOFILTERPTYPE, NULL, 0, TRUE, NULL);
  825. else
  826. rc = NO_ERROR;
  827. break;
  828. /** Set piggyback wait for backtraffic flag **/
  829. case IPX_IMMEDIATESPXACK:
  830. /** Get the optvalue as an INT **/
  831. rc = *(INT *)optvalue;
  832. /** **/
  833. if (rc)
  834. {
  835. /** Turn it ON **/
  836. rc = WSAEINVAL;
  837. if ((ct->con_socktype == SOCK_STREAM) ||
  838. (ct->con_socktype == SOCK_SEQPACKET))
  839. {
  840. rc = NO_ERROR;
  841. ct->con_flags |= WSHCON_IMM_SPXACK;
  842. if (addrhandle)
  843. rc = do_tdi_action(addrhandle, MSPX_NOACKWAIT, NULL, 0, TRUE, NULL);
  844. }
  845. }
  846. else
  847. {
  848. /** Turn it OFF **/
  849. rc = WSAEINVAL;
  850. if ((ct->con_socktype == SOCK_STREAM) ||
  851. (ct->con_socktype == SOCK_SEQPACKET))
  852. {
  853. rc = NO_ERROR;
  854. ct->con_flags &= ~WSHCON_IMM_SPXACK;
  855. if (addrhandle)
  856. rc = do_tdi_action(addrhandle, MSPX_ACKWAIT, NULL, 0, TRUE, NULL);
  857. }
  858. }
  859. /** Return the result **/
  860. return rc;
  861. /** Set to recv pcol hdrs with data **/
  862. case IPX_RECVHDR:
  863. /** Get the optvalue as an INT **/
  864. rc = *(INT *)optvalue;
  865. if (rc)
  866. {
  867. /** Turn it ON **/
  868. ct->con_flags |= WSHCON_SENDHDR;
  869. /** Send it to the driver **/
  870. rc = WSAEINVAL;
  871. if (ct->con_socktype == SOCK_DGRAM)
  872. {
  873. rc = NO_ERROR;
  874. if (addrhandle)
  875. rc = do_tdi_action(addrhandle, MIPX_SENDHEADER, NULL, 0, TRUE, NULL);
  876. }
  877. else if ((ct->con_socktype == SOCK_STREAM) ||
  878. (ct->con_socktype == SOCK_SEQPACKET))
  879. {
  880. /** Do this on address handle **/
  881. rc = NO_ERROR;
  882. if (addrhandle)
  883. rc = do_tdi_action(addrhandle, MSPX_SENDHEADER, NULL, 0, TRUE, NULL);
  884. }
  885. }
  886. else
  887. {
  888. /** Turn it OFF **/
  889. ct->con_flags &= ~WSHCON_SENDHDR;
  890. /** Send it to the driver **/
  891. rc = WSAEINVAL;
  892. if (ct->con_socktype == SOCK_DGRAM)
  893. {
  894. rc = NO_ERROR;
  895. if (addrhandle)
  896. rc = do_tdi_action(addrhandle, MIPX_NOSENDHEADER, NULL, 0, TRUE, NULL);
  897. }
  898. else if ((ct->con_socktype == SOCK_STREAM) ||
  899. (ct->con_socktype == SOCK_SEQPACKET))
  900. {
  901. rc = NO_ERROR;
  902. if (addrhandle)
  903. rc = do_tdi_action(addrhandle, MSPX_NOSENDHEADER, NULL, 0, TRUE, NULL);
  904. }
  905. }
  906. /** Return the result **/
  907. return rc;
  908. /** Set the Datastream type to send pkts with **/
  909. case IPX_DSTYPE:
  910. /** Make sure length is OK **/
  911. if (optlength < sizeof(INT))
  912. return WSAEFAULT;
  913. /** Make sure this is for a STREAM socket **/
  914. if ((ct->con_socktype != SOCK_STREAM) &&
  915. (ct->con_socktype != SOCK_SEQPACKET)) {
  916. return WSAEINVAL;
  917. }
  918. /** Get the value and check it **/
  919. rc = *(INT *)optvalue;
  920. if ((rc < 0) || (rc > 255))
  921. return WSAEINVAL;
  922. /** Save the new value **/
  923. ct->con_dstype = (UCHAR)rc;
  924. /** Send the new value down to the driver **/
  925. if (connhandle)
  926. rc = do_tdi_action(connhandle, MSPX_SETDATASTREAM, &ct->con_dstype, 1, FALSE, NULL);
  927. else
  928. rc = 0;
  929. /** **/
  930. return rc;
  931. /** Set the extended address option **/
  932. case IPX_EXTENDED_ADDRESS:
  933. /** Make sure length is OK **/
  934. if (optlength < sizeof(INT))
  935. return WSAEFAULT;
  936. /** Make sure this is for a DGRAM socket **/
  937. if (ct->con_socktype != SOCK_DGRAM)
  938. return WSAEINVAL;
  939. /** Get the optvalue as an INT **/
  940. rc = *(INT *)optvalue;
  941. /** **/
  942. if (rc) {
  943. /** Send the option down to the driver **/
  944. ct->con_flags |= WSHCON_EXTADDR;
  945. if (addrhandle)
  946. rc = do_tdi_action(addrhandle, MIPX_SENDADDROPT, NULL, 0, TRUE, NULL);
  947. else
  948. rc = NO_ERROR;
  949. }
  950. else {
  951. /** Send the option down to the driver **/
  952. ct->con_flags &= ~WSHCON_EXTADDR;
  953. if (addrhandle)
  954. rc = do_tdi_action(addrhandle, MIPX_NOSENDADDROPT, NULL, 0, TRUE, NULL);
  955. else
  956. rc = NO_ERROR;
  957. }
  958. return rc;
  959. /** Set the broadcast reception **/
  960. case IPX_RECEIVE_BROADCAST:
  961. /** Make sure length is OK **/
  962. if (optlength < sizeof(INT))
  963. return WSAEFAULT;
  964. /** Make sure this is for a DGRAM socket **/
  965. if (ct->con_socktype != SOCK_DGRAM)
  966. return WSAEINVAL;
  967. /** Get the optvalue as an INT **/
  968. rc = *(INT *)optvalue;
  969. /** **/
  970. if (rc) {
  971. /** Send the option down to the driver **/
  972. ct->con_flags |= WSHCON_RCVBCAST;
  973. if (addrhandle)
  974. rc = do_tdi_action(addrhandle, MIPX_RCVBCAST, NULL, 0, TRUE, NULL);
  975. else
  976. rc = NO_ERROR;
  977. }
  978. else {
  979. /** Send the option down to the driver **/
  980. ct->con_flags &= ~WSHCON_RCVBCAST;
  981. if (addrhandle)
  982. rc = do_tdi_action(addrhandle, MIPX_NORCVBCAST, NULL, 0, TRUE, NULL);
  983. else
  984. rc = NO_ERROR;
  985. }
  986. return rc;
  987. /** All others return error **/
  988. default:
  989. return WSAENOPROTOOPT;
  990. }
  991. /** All Done OK **/
  992. return NO_ERROR;
  993. }
  994. /*page***************************************************************
  995. W S H G e t W i l d c a r d S o c k a d d r
  996. This routing returns a wilcard socket address for the
  997. sockets DLL to use.
  998. Arguments - context = Context ptr from WSAOpenSocket
  999. addrp = Ptr to where to store the address
  1000. addrlen = Ptr to where to store length of address
  1001. Returns - NO_ERROR = Operation succeeded OK
  1002. Else = WinSock error code
  1003. *********************************************************************/
  1004. INT WSHGetWildcardSockaddr(PVOID context, PSOCKADDR addrp, PINT addrlen)
  1005. {
  1006. /**
  1007. Setup the address as the address family +
  1008. all 0's for the rest.
  1009. **/
  1010. memset(addrp, 0, sizeof(SOCKADDR));
  1011. addrp->sa_family = AF_NS;
  1012. /** Set the address length **/
  1013. *addrlen = sizeof(SOCKADDR);
  1014. /** Return OK **/
  1015. return NO_ERROR;
  1016. }
  1017. /*page***************************************************************
  1018. i s _ t r i p l e _ i n _ l i s t
  1019. Check to see if the given triple is in the given
  1020. triple list.
  1021. Arguments - tlist = Ptr to the triple list
  1022. tlen = Num entries in the triple list
  1023. addrfam = Address family to look for
  1024. socktype = Socket Type to look for
  1025. pcol = Protocol to look for
  1026. Returns - TRUE = Yes
  1027. FALSE = No
  1028. *********************************************************************/
  1029. BOOLEAN is_triple_in_list(PMAPPING_TRIPLE tlist, ULONG tlen,
  1030. INT addrfam, INT socktype, INT pcol)
  1031. {
  1032. ULONG i;
  1033. /**
  1034. Go thru the list and search to see if we can
  1035. find the given triple in the list.
  1036. **/
  1037. for (i = 0 ; i < tlen ; i++,tlist++) {
  1038. /** If it matches - return OK **/
  1039. if ((addrfam == tlist->triple_addrfam) &&
  1040. (socktype == tlist->triple_socktype) &&
  1041. (pcol == tlist->triple_protocol))
  1042. return TRUE;
  1043. }
  1044. /** Not Found **/
  1045. return FALSE;
  1046. }
  1047. /*page***************************************************************
  1048. W S H E n u m P r o t o c o l s
  1049. Enumerates IPX/SPX protocols.
  1050. Returns - NO_ERROR or an error code.
  1051. *********************************************************************/
  1052. INT
  1053. WSHEnumProtocols (
  1054. IN LPINT lpiProtocols,
  1055. IN LPTSTR lpTransportKeyName,
  1056. IN OUT LPVOID lpProtocolBuffer,
  1057. IN OUT LPDWORD lpdwBufferLength
  1058. )
  1059. {
  1060. DWORD bytesRequired;
  1061. PPROTOCOL_INFOW protocolInfo;
  1062. BOOL useSpx = FALSE;
  1063. BOOL useSpx2 = FALSE;
  1064. BOOL useIpx = FALSE;
  1065. BOOL spxString;
  1066. DWORD i;
  1067. PWCHAR namePtr;
  1068. INT entriesReturned = 0;
  1069. //
  1070. // Determine whether we should return information for IPX or SPX.
  1071. //
  1072. if ( _wcsicmp( L"NwlnkIpx", (LPWSTR)lpTransportKeyName ) == 0 ) {
  1073. spxString = FALSE;
  1074. } else {
  1075. spxString = TRUE;
  1076. }
  1077. //
  1078. // Make sure that the caller cares about SPX, SPX2, and/or IPX.
  1079. //
  1080. if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
  1081. for ( i = 0; lpiProtocols[i] != 0; i++ ) {
  1082. if ( lpiProtocols[i] == NSPROTO_SPX && spxString ) {
  1083. useSpx = TRUE;
  1084. }
  1085. if ( lpiProtocols[i] == NSPROTO_SPXII && spxString ) {
  1086. useSpx2 = TRUE;
  1087. }
  1088. if ( lpiProtocols[i] == NSPROTO_IPX && !spxString ) {
  1089. useIpx = TRUE;
  1090. }
  1091. }
  1092. } else {
  1093. useSpx = FALSE;
  1094. useSpx2 = spxString;
  1095. useIpx = !spxString;
  1096. }
  1097. if ( !useSpx && !useSpx2 && !useIpx ) {
  1098. *lpdwBufferLength = 0;
  1099. return 0;
  1100. }
  1101. //
  1102. // Make sure that the caller has specified a sufficiently large
  1103. // buffer.
  1104. //
  1105. bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 3) +
  1106. ( (wcslen( SPX_NAME ) + 1) * sizeof(WCHAR)) +
  1107. ( (wcslen( SPX2_NAME ) + 1) * sizeof(WCHAR)) +
  1108. ( (wcslen( IPX_NAME ) + 1) * sizeof(WCHAR)));
  1109. if ( bytesRequired > *lpdwBufferLength ) {
  1110. *lpdwBufferLength = bytesRequired;
  1111. return -1;
  1112. }
  1113. //
  1114. // Initialize local variables.
  1115. //
  1116. protocolInfo = lpProtocolBuffer;
  1117. namePtr = (PWCHAR)( (PCHAR)lpProtocolBuffer + *lpdwBufferLength );
  1118. //
  1119. // Fill in SPX info, if requested.
  1120. //
  1121. if ( useSpx ) {
  1122. entriesReturned += 1;
  1123. protocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
  1124. XP_MESSAGE_ORIENTED |
  1125. XP_PSEUDO_STREAM |
  1126. XP_GUARANTEED_ORDER |
  1127. XP_FRAGMENTATION;
  1128. protocolInfo->iAddressFamily = AF_IPX;
  1129. protocolInfo->iMaxSockAddr = 0x10;
  1130. protocolInfo->iMinSockAddr = 0xE;
  1131. protocolInfo->iSocketType = SOCK_SEQPACKET;
  1132. protocolInfo->iProtocol = NSPROTO_SPX;
  1133. protocolInfo->dwMessageSize = 0xFFFFFFFF;
  1134. namePtr = namePtr - (wcslen( SPX_NAME) + 1);
  1135. protocolInfo->lpProtocol = namePtr;
  1136. wcscpy( protocolInfo->lpProtocol, SPX_NAME );
  1137. protocolInfo += 1;
  1138. }
  1139. //
  1140. // Fill in SPX II info, if requested.
  1141. //
  1142. if ( useSpx2 ) {
  1143. entriesReturned += 1;
  1144. protocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
  1145. XP_MESSAGE_ORIENTED |
  1146. XP_PSEUDO_STREAM |
  1147. XP_GRACEFUL_CLOSE |
  1148. XP_GUARANTEED_ORDER |
  1149. XP_FRAGMENTATION;
  1150. protocolInfo->iAddressFamily = AF_IPX;
  1151. protocolInfo->iMaxSockAddr = 0x10;
  1152. protocolInfo->iMinSockAddr = 0xE;
  1153. protocolInfo->iSocketType = SOCK_SEQPACKET;
  1154. protocolInfo->iProtocol = NSPROTO_SPXII;
  1155. protocolInfo->dwMessageSize = 0xFFFFFFFF;
  1156. namePtr = namePtr - (wcslen( SPX2_NAME) + 1);
  1157. protocolInfo->lpProtocol = namePtr;
  1158. wcscpy( protocolInfo->lpProtocol, SPX2_NAME );
  1159. protocolInfo += 1;
  1160. }
  1161. //
  1162. // Fill in IPX info, if requested.
  1163. //
  1164. if ( useIpx ) {
  1165. entriesReturned += 1;
  1166. protocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
  1167. XP_MESSAGE_ORIENTED |
  1168. XP_SUPPORTS_BROADCAST |
  1169. XP_SUPPORTS_MULTICAST |
  1170. XP_FRAGMENTATION;
  1171. protocolInfo->iAddressFamily = AF_IPX;
  1172. protocolInfo->iMaxSockAddr = 0x10;
  1173. protocolInfo->iMinSockAddr = 0xE;
  1174. protocolInfo->iSocketType = SOCK_DGRAM;
  1175. protocolInfo->iProtocol = NSPROTO_IPX;
  1176. protocolInfo->dwMessageSize = 576;
  1177. namePtr = namePtr - (wcslen( IPX_NAME) + 1);
  1178. protocolInfo->lpProtocol = namePtr;
  1179. wcscpy( protocolInfo->lpProtocol, IPX_NAME );
  1180. }
  1181. *lpdwBufferLength = bytesRequired;
  1182. return entriesReturned;
  1183. } // WSHEnumProtocols
  1184. #define _IPX_CONTROL_CODE(request,method) \
  1185. CTL_CODE(FILE_DEVICE_TRANSPORT, request, method, FILE_ANY_ACCESS)
  1186. #define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
  1187. DWORD
  1188. WshLoadSpx(
  1189. VOID
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. Starts the nwlnkspx.sys driver by submitting a special ioctl
  1194. to ipx, which calls ZwLoadDriver() for us.
  1195. Arguments:
  1196. none
  1197. Returns:
  1198. Error return from the load operation.
  1199. ++*/
  1200. {
  1201. DWORD err = NO_ERROR;
  1202. HANDLE FileHandle;
  1203. OBJECT_ATTRIBUTES ObjectAttributes;
  1204. IO_STATUS_BLOCK IoStatusBlock;
  1205. UNICODE_STRING FileString;
  1206. WCHAR FileName[] = L"\\Device\\NwlnkIpx";
  1207. NTSTATUS Status;
  1208. RtlInitUnicodeString (&FileString, FileName);
  1209. InitializeObjectAttributes(
  1210. &ObjectAttributes,
  1211. &FileString,
  1212. OBJ_CASE_INSENSITIVE,
  1213. NULL,
  1214. NULL);
  1215. Status = NtOpenFile(
  1216. &FileHandle,
  1217. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  1218. &ObjectAttributes,
  1219. &IoStatusBlock,
  1220. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1221. FILE_SYNCHRONOUS_IO_ALERT);
  1222. if (!NT_SUCCESS(Status)) {
  1223. err = ERROR_FILE_NOT_FOUND;
  1224. } else {
  1225. Status = NtDeviceIoControlFile(
  1226. FileHandle,
  1227. NULL,
  1228. NULL,
  1229. NULL,
  1230. &IoStatusBlock,
  1231. IOCTL_IPX_LOAD_SPX,
  1232. NULL,
  1233. 0,
  1234. NULL,
  1235. 0);
  1236. if (Status == STATUS_IMAGE_ALREADY_LOADED) {
  1237. err = ERROR_SERVICE_ALREADY_RUNNING;
  1238. //
  1239. // #36451
  1240. // If the service controller loads SPX ("net start nwlnkspx", or due to dependency of RPC on SPX)
  1241. // then we get this error the first time too. Keep a note of that.
  1242. //
  1243. // NOTE: we still leak a handle per process since the handle to the driver is actually created
  1244. // in the system process' context. The ideal way to fix this should be to have IPX associate the
  1245. // handle with the current process (so handle is destroyed when the process dies) or to have the
  1246. // dll tell IPX to close the handle it opened earlier.
  1247. //
  1248. SpxLoaded = TRUE;
  1249. } else if (!NT_SUCCESS(Status)) {
  1250. err = ERROR_IO_DEVICE;
  1251. } else {
  1252. SpxLoaded = TRUE;
  1253. }
  1254. NtClose (FileHandle);
  1255. }
  1256. return(err);
  1257. }
  1258. /*page***************************************************************
  1259. W S H G e t P r o v i d e r G u i d
  1260. Queries the GUID identifier for this protocol.
  1261. Returns - NO_ERROR or an error code.
  1262. *********************************************************************/
  1263. INT
  1264. WINAPI
  1265. WSHGetProviderGuid (
  1266. IN LPWSTR ProviderName,
  1267. OUT LPGUID ProviderGuid
  1268. )
  1269. {
  1270. if( ProviderName == NULL ||
  1271. ProviderGuid == NULL ) {
  1272. return WSAEFAULT;
  1273. }
  1274. if( _wcsicmp( ProviderName, L"NwlnkIpx" ) == 0 ) {
  1275. RtlCopyMemory(
  1276. ProviderGuid,
  1277. &IpxProviderGuid,
  1278. sizeof(GUID)
  1279. );
  1280. return NO_ERROR;
  1281. }
  1282. if( _wcsicmp( ProviderName, L"NwlnkSpx" ) == 0 ) {
  1283. RtlCopyMemory(
  1284. ProviderGuid,
  1285. &SpxProviderGuid,
  1286. sizeof(GUID)
  1287. );
  1288. return NO_ERROR;
  1289. }
  1290. return WSAEINVAL;
  1291. } // WSHGetProviderGuid
  1292. INT
  1293. WINAPI
  1294. WSHAddressToString (
  1295. IN LPSOCKADDR Address,
  1296. IN INT AddressLength,
  1297. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  1298. OUT LPWSTR AddressString,
  1299. IN OUT LPDWORD AddressStringLength
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. Converts a SOCKADDR to a human-readable form.
  1304. Arguments:
  1305. Address - The SOCKADDR to convert.
  1306. AddressLength - The length of Address.
  1307. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  1308. AddressString - Receives the formatted address string.
  1309. AddressStringLength - On input, contains the length of AddressString.
  1310. On output, contains the number of characters actually written
  1311. to AddressString.
  1312. Return Value:
  1313. INT - 0 if successful, WinSock error code if not.
  1314. --*/
  1315. {
  1316. WCHAR string[BUFFER_SIZE];
  1317. INT length;
  1318. LPSOCKADDR_IPX addr;
  1319. //
  1320. // Quick sanity checks.
  1321. //
  1322. if( Address == NULL ||
  1323. AddressLength < sizeof(SOCKADDR_IPX) ||
  1324. AddressString == NULL ||
  1325. AddressStringLength == NULL ) {
  1326. return WSAEFAULT;
  1327. }
  1328. addr = (LPSOCKADDR_IPX)Address;
  1329. if( addr->sa_family != AF_NS ) {
  1330. return WSAEINVAL;
  1331. }
  1332. length = swprintf(
  1333. string,
  1334. L"%2.2x%2.2x%2.2x%2.2x.%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
  1335. (UCHAR) addr->sa_netnum[0],
  1336. (UCHAR) addr->sa_netnum[1],
  1337. (UCHAR) addr->sa_netnum[2],
  1338. (UCHAR) addr->sa_netnum[3],
  1339. (UCHAR) addr->sa_nodenum[0],
  1340. (UCHAR) addr->sa_nodenum[1],
  1341. (UCHAR) addr->sa_nodenum[2],
  1342. (UCHAR) addr->sa_nodenum[3],
  1343. (UCHAR) addr->sa_nodenum[4],
  1344. (UCHAR) addr->sa_nodenum[5]
  1345. );
  1346. if( addr->sa_socket != 0 ) {
  1347. length += swprintf(
  1348. string + length,
  1349. L":%hu",
  1350. ntohs( addr->sa_socket )
  1351. );
  1352. }
  1353. length++; // account for terminator
  1354. if ( length > BUFFER_SIZE ) {
  1355. DbgPrint("length exceeded internal buffer in wshisn.dll.\n");
  1356. return WSAEFAULT;
  1357. }
  1358. if( *AddressStringLength < (DWORD)length ) {
  1359. DbgPrint("AddressStringLength %lu < length %lu\n",*AddressStringLength, length);
  1360. return WSAEFAULT;
  1361. }
  1362. *AddressStringLength = (DWORD)length;
  1363. RtlCopyMemory(
  1364. AddressString,
  1365. string,
  1366. length * sizeof(WCHAR)
  1367. );
  1368. return NO_ERROR;
  1369. } // WSHAddressToString