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.

692 lines
16 KiB

  1. #include "precomp.h"
  2. #include <malloc.h>
  3. #include <ssdp.h>
  4. #include <iptypes.h>
  5. #include <iphlpapi.h>
  6. #include <mswsock.h>
  7. #ifdef IP_OBEX
  8. #define Trace1 DbgPrint
  9. GUID gWsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
  10. #define MAX_ADDRESSES (16)
  11. typedef struct _NLA_ADDRESS_LIST {
  12. LONG AddressCount;
  13. sockaddr_in Address[MAX_ADDRESSES];
  14. } NLA_ADDRESS_LIST, *PNLA_ADDRESS_LIST;
  15. BOOL
  16. GetIpAddressFromAdapterName(
  17. CHAR *AdapterName,
  18. ULONG *IpAddress
  19. );
  20. VOID
  21. AddressListChangeHandler(
  22. DWORD Error,
  23. DWORD BytesTransfered,
  24. LPWSAOVERLAPPED WsOverLapped,
  25. DWORD Flags
  26. );
  27. DWORD
  28. NetWorkWorker(
  29. PVOID Context
  30. );
  31. typedef struct _ADDRESS_ENTRY {
  32. in_addr IpAddress;
  33. PVOID AddressContext;
  34. HANDLE SsdpHandle;
  35. BOOL InUse;
  36. BOOL Present;
  37. BOOL Reported;
  38. CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
  39. NLA_CONNECTIVITY_TYPE Type;
  40. } ADDRESS_ENTRY, *PADDRESS_ENTRY;
  41. typedef struct _NET_CONTROL {
  42. LONG ReferenceCount;
  43. BOOL Closing;
  44. HANDLE QueryHandle;
  45. WSAOVERLAPPED WsOverlapped;
  46. HANDLE RegistrationContext;
  47. NEW_ADDRESS_CALLBACK NewAddressCallback;
  48. ADDRESS_GONE_CALLBACK AddressGoneCallback;
  49. ADDRESS_ENTRY AddressEntry[MAX_ADDRESSES];
  50. } NET_CONTROL, *PNET_CONTROL;
  51. VOID
  52. GetAddressList(
  53. PNET_CONTROL NetControl,
  54. HANDLE QueryHandle
  55. );
  56. VOID
  57. RemoveReferenceOnNetControl(
  58. PNET_CONTROL NetControl
  59. )
  60. {
  61. LONG CurrentCount;
  62. CurrentCount=InterlockedDecrement(&NetControl->ReferenceCount);
  63. if (CurrentCount == 0) {
  64. HeapFree(GetProcessHeap(),0,NetControl);
  65. }
  66. return;
  67. }
  68. VOID
  69. UnRegisterForAdhocNetworksNotification(
  70. HANDLE RegistrationHandle
  71. )
  72. {
  73. PNET_CONTROL NetControl=(PNET_CONTROL)RegistrationHandle;
  74. NetControl->Closing=TRUE;
  75. WSALookupServiceEnd(NetControl->QueryHandle);
  76. RemoveReferenceOnNetControl(NetControl);
  77. return;
  78. }
  79. HANDLE
  80. RegisterForAdhocNetworksNotification(
  81. HANDLE RegistrationContext,
  82. NEW_ADDRESS_CALLBACK NewAddressCallback,
  83. ADDRESS_GONE_CALLBACK AddressGoneCallback
  84. )
  85. {
  86. PNET_CONTROL NetControl=NULL;
  87. WORD wVersionRequested;
  88. WSADATA wsaData;
  89. int err;
  90. BOOL bResult;
  91. int j;
  92. LONG Status;
  93. NetControl=(PNET_CONTROL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*NetControl));
  94. if (NetControl == NULL) {
  95. goto CleanUp;
  96. }
  97. NetControl->NewAddressCallback=NewAddressCallback;
  98. NetControl->AddressGoneCallback=AddressGoneCallback;
  99. NetControl->RegistrationContext=RegistrationContext;
  100. for (j=0; j< MAX_ADDRESSES; j++) {
  101. NetControl->AddressEntry[j].InUse=FALSE;
  102. }
  103. WSAQUERYSET restrictions;
  104. ZeroMemory(&restrictions, sizeof(restrictions));
  105. restrictions.dwSize = sizeof(restrictions);
  106. restrictions.lpServiceClassId = &gWsMobilityServiceClassGuid;
  107. restrictions.dwNameSpace = NS_NLA;
  108. Status = WSALookupServiceBegin(
  109. &restrictions,
  110. LUP_NOCONTAINERS | LUP_RETURN_ALL | LUP_DEEP ,
  111. &NetControl->QueryHandle
  112. );
  113. if (Status != ERROR_SUCCESS) {
  114. goto CleanUp;
  115. }
  116. //
  117. // one refcount for the creation of the object
  118. //
  119. NetControl->ReferenceCount=1;
  120. //
  121. // add one refcount for the workitem
  122. //
  123. InterlockedIncrement(&NetControl->ReferenceCount);
  124. bResult=QueueUserWorkItem(
  125. NetWorkWorker,
  126. NetControl,
  127. WT_EXECUTEINIOTHREAD
  128. );
  129. if (bResult) {
  130. return NetControl;
  131. }
  132. CleanUp:
  133. if (NetControl != NULL) {
  134. HeapFree(GetProcessHeap(),0,NetControl);
  135. }
  136. return NULL;
  137. }
  138. DWORD
  139. NetWorkWorker(
  140. PVOID Context
  141. )
  142. {
  143. PNET_CONTROL NetControl=(PNET_CONTROL)Context;
  144. int err;
  145. DWORD BytesReturned;
  146. BOOL bResult;
  147. GetAddressList(NetControl,NetControl->QueryHandle);
  148. ZeroMemory(&NetControl->WsOverlapped,sizeof(NetControl->WsOverlapped));
  149. NetControl->WsOverlapped.hEvent=NetControl;
  150. WSACOMPLETION Completion;
  151. Completion.Type=NSP_NOTIFY_APC;
  152. Completion.Parameters.Apc.lpOverlapped=&NetControl->WsOverlapped;
  153. Completion.Parameters.Apc.lpfnCompletionProc=AddressListChangeHandler;
  154. err=WSANSPIoctl(
  155. NetControl->QueryHandle,
  156. SIO_NSP_NOTIFY_CHANGE,
  157. NULL,
  158. 0,
  159. NULL,
  160. 0,
  161. &BytesReturned,
  162. &Completion
  163. );
  164. if (err == SOCKET_ERROR) {
  165. if (WSAGetLastError() != WSA_IO_PENDING) {
  166. //
  167. // the call failed and return value was not pending
  168. //
  169. RemoveReferenceOnNetControl(NetControl);
  170. }
  171. }
  172. return 0;
  173. }
  174. VOID
  175. AddressListChangeHandler(
  176. DWORD Error,
  177. DWORD BytesTransfered,
  178. LPWSAOVERLAPPED WsOverlapped,
  179. DWORD Flags
  180. )
  181. {
  182. PNET_CONTROL NetControl=(PNET_CONTROL)WsOverlapped->hEvent;
  183. if (!NetControl->Closing) {
  184. NetWorkWorker(
  185. NetControl
  186. );
  187. } else {
  188. //
  189. // we are closing, remove all the addresses
  190. //
  191. ULONG i;
  192. for (i=0; i< MAX_ADDRESSES; i++) {
  193. //
  194. // See if any address disappeared
  195. //
  196. if (NetControl->AddressEntry[i].InUse) {
  197. //
  198. // was in use at one time
  199. //
  200. if (NetControl->AddressEntry[i].Reported) {
  201. DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
  202. (NetControl->AddressGoneCallback)(
  203. NetControl->RegistrationContext,
  204. NetControl->AddressEntry[i].AddressContext
  205. );
  206. UnregisterWithSsdp(
  207. NetControl->AddressEntry[i].SsdpHandle
  208. );
  209. ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i]));
  210. }
  211. }
  212. }
  213. RemoveReferenceOnNetControl(NetControl);
  214. }
  215. return;
  216. }
  217. VOID
  218. AddAddressToList(
  219. PNET_CONTROL NetControl,
  220. CHAR *AdapterName,
  221. in_addr IpAddress,
  222. NLA_CONNECTIVITY_TYPE Type
  223. )
  224. {
  225. ULONG j;
  226. ULONG i;
  227. LONG FreeSlot;
  228. BOOL bResult;
  229. for (j=0; j< MAX_ADDRESSES; j++) {
  230. if (NetControl->AddressEntry[j].InUse) {
  231. // if (NetControl->AddressEntry[j].IpAddress.S_un.S_addr == IpAddress.S_un.S_addr) {
  232. if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[j].AdapterName)) {
  233. //
  234. // we have already seen this address
  235. //
  236. DbgPrint("net: dup local address %s\n",inet_ntoa(IpAddress));
  237. NetControl->AddressEntry[j].Present=TRUE;
  238. break;
  239. }
  240. } else {
  241. FreeSlot=j;
  242. }
  243. }
  244. if (j == MAX_ADDRESSES) {
  245. //
  246. // we have a new address
  247. //
  248. SOCKET ListenSocket;
  249. NetControl->AddressEntry[FreeSlot].InUse=TRUE;
  250. NetControl->AddressEntry[FreeSlot].Present=TRUE;
  251. NetControl->AddressEntry[FreeSlot].IpAddress = IpAddress;
  252. lstrcpyA(NetControl->AddressEntry[FreeSlot].AdapterName,AdapterName);
  253. NetControl->AddressEntry[FreeSlot].Type=Type;
  254. if (((IpAddress.S_un.S_addr != INADDR_NONE) && (IpAddress.S_un.S_addr != 0)) &&
  255. ((Type == NLA_NETWORK_AD_HOC)
  256. ||
  257. (Type == NLA_NETWORK_UNMANAGED))) {
  258. NetControl->AddressEntry[FreeSlot].Reported=TRUE;
  259. bResult=RegisterWithSsdp(
  260. &IpAddress,
  261. &ListenSocket,
  262. &NetControl->AddressEntry[FreeSlot].SsdpHandle,
  263. 650
  264. );
  265. if (!bResult) {
  266. DbgPrint("IRMON: failed to register with ssdp\n");
  267. NetControl->AddressEntry[FreeSlot].Reported=FALSE;
  268. } else {
  269. (NetControl->NewAddressCallback)(
  270. NetControl->RegistrationContext,
  271. ListenSocket,
  272. &NetControl->AddressEntry[FreeSlot].AddressContext
  273. );
  274. }
  275. }
  276. }
  277. return;
  278. }
  279. VOID
  280. RemoveAddressFromList(
  281. PNET_CONTROL NetControl,
  282. CHAR *AdapterName
  283. )
  284. {
  285. ULONG i;
  286. for (i=0; i< MAX_ADDRESSES; i++) {
  287. //
  288. // See if any address disappeared
  289. //
  290. if (NetControl->AddressEntry[i].InUse) {
  291. //
  292. // was in use at one time
  293. //
  294. if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[i].AdapterName)) {
  295. //
  296. // This matched the device that is being removed
  297. //
  298. if (NetControl->AddressEntry[i].Reported) {
  299. //
  300. // this one was reported to the client
  301. //
  302. DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
  303. (NetControl->AddressGoneCallback)(
  304. NetControl->RegistrationContext,
  305. NetControl->AddressEntry[i].AddressContext
  306. );
  307. UnregisterWithSsdp(
  308. NetControl->AddressEntry[i].SsdpHandle
  309. );
  310. }
  311. ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i]));
  312. }
  313. }
  314. }
  315. return;
  316. }
  317. VOID
  318. GetAddressList(
  319. PNET_CONTROL NetControl,
  320. HANDLE QueryHandle
  321. )
  322. {
  323. int ret = FALSE;
  324. WSADATA wsaData;
  325. PWSAQUERYSET result = NULL;
  326. DWORD length;
  327. DWORD LengthRequested;
  328. int error;
  329. ret = TRUE;
  330. while (1) {
  331. length = 0;
  332. WSALookupServiceNext(QueryHandle, 0, &length, NULL);
  333. if (((error = WSAGetLastError()) != WSAEFAULT) && (error != WSA_E_NO_MORE)) {
  334. Trace1("WSALookupServiceNext1 failed %d\n", error);
  335. ret = FALSE;
  336. break;
  337. }
  338. result = (PWSAQUERYSET)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,length);
  339. if (result != NULL) {
  340. LengthRequested=length;
  341. ret = WSALookupServiceNext(QueryHandle, 0, &length, result);
  342. if (ret == ERROR_SUCCESS) {
  343. if (result->lpBlob != NULL) {
  344. NLA_BLOB *blob = (NLA_BLOB *)result->lpBlob->pBlobData;
  345. int next;
  346. IN_ADDR IpAddress;
  347. NLA_CONNECTIVITY_TYPE ConnectivityType=NLA_NETWORK_UNKNOWN;
  348. CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
  349. AdapterName[0]='\0';
  350. IpAddress.S_un.S_addr=INADDR_NONE;
  351. do {
  352. // The next four lines need changing when network interface type is implemented
  353. DbgPrint("NLA: Blob type %d\n",blob->header.type);
  354. if (blob->header.type == NLA_CONNECTIVITY) {
  355. DbgPrint("NLA: connectivity=%d, Internet=%d\n",blob->data.connectivity.type,blob->data.connectivity.internet);
  356. ConnectivityType=blob->data.connectivity.type;
  357. }
  358. if (blob->header.type == NLA_INTERFACE) {
  359. DbgPrint("NLA: adapter name %s, speed %d\n",blob->data.interfaceData.adapterName,blob->data.interfaceData.dwSpeed);
  360. GetIpAddressFromAdapterName(blob->data.interfaceData.adapterName,&IpAddress.S_un.S_addr);
  361. lstrcpynA(AdapterName,blob->data.interfaceData.adapterName,sizeof(AdapterName)-1);
  362. }
  363. next = blob->header.nextOffset;
  364. blob = (NLA_BLOB *)(((char *)blob) + next);
  365. } while(next != 0);
  366. if (AdapterName[0] != '\0') {
  367. //
  368. // we got an adapter name
  369. //
  370. if (result->dwOutputFlags & RESULT_IS_ADDED) {
  371. //
  372. // new interface
  373. //
  374. DbgPrint("NLA: add\n");
  375. AddAddressToList(
  376. NetControl,
  377. AdapterName,
  378. IpAddress,
  379. ConnectivityType
  380. );
  381. } else {
  382. if (result->dwOutputFlags & RESULT_IS_DELETED) {
  383. DbgPrint("NLA: delete\n");
  384. RemoveAddressFromList(
  385. NetControl,
  386. AdapterName
  387. );
  388. } else {
  389. if (result->dwOutputFlags & RESULT_IS_CHANGED) {
  390. DbgPrint("NLA: change\n");
  391. RemoveAddressFromList(
  392. NetControl,
  393. AdapterName
  394. );
  395. AddAddressToList(
  396. NetControl,
  397. AdapterName,
  398. IpAddress,
  399. ConnectivityType
  400. );
  401. } else {
  402. DbgPrint("NLA: other dwOutputFlags %x\n",result->dwOutputFlags);
  403. }
  404. }
  405. }
  406. }
  407. }
  408. } else {
  409. if ((error = WSAGetLastError()) != WSA_E_NO_MORE) {
  410. Trace1("WSALookupServiceNext failed %d, needed=%d, req=%d\n", error,length, LengthRequested);
  411. ret = FALSE;
  412. }
  413. break;
  414. }
  415. HeapFree(GetProcessHeap(),0,result);
  416. result=NULL;
  417. }
  418. }
  419. return ;
  420. }
  421. BOOL
  422. GetIpAddressFromAdapterName(
  423. CHAR *AdapterName,
  424. ULONG *IpAddress
  425. )
  426. {
  427. PIP_ADAPTER_INFO AdapterInfo;
  428. PIP_ADAPTER_INFO CurrentAdapter;
  429. ULONG BufferNeeded;
  430. DWORD ReturnValue;
  431. BOOL bReturn=FALSE;
  432. BufferNeeded=0;
  433. // DbgPrint("irmon: GetIpAddressFromAdapterName\n");
  434. ReturnValue=GetAdaptersInfo(
  435. NULL,
  436. &BufferNeeded
  437. );
  438. if (ReturnValue != ERROR_BUFFER_OVERFLOW) {
  439. //
  440. // failed for some other reason
  441. //
  442. DbgPrint("irmon: GetAdaptersInfo(1) failed\n");
  443. return FALSE;
  444. }
  445. AdapterInfo=(PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,BufferNeeded);
  446. if (AdapterInfo != NULL) {
  447. ReturnValue=GetAdaptersInfo(
  448. AdapterInfo,
  449. &BufferNeeded
  450. );
  451. if (ReturnValue == ERROR_SUCCESS) {
  452. CurrentAdapter=AdapterInfo;
  453. while (CurrentAdapter != NULL) {
  454. int Match;
  455. // DbgPrint("IRMON: comp AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
  456. Match=lstrcmpiA(AdapterName,CurrentAdapter->AdapterName);
  457. if (Match == 0) {
  458. DbgPrint("IRMON: match AdapterName=%s, ip=%s\n",CurrentAdapter->AdapterName,CurrentAdapter->IpAddressList.IpAddress.String);
  459. *IpAddress=inet_addr(&CurrentAdapter->IpAddressList.IpAddress.String[0]);
  460. if (*IpAddress != INADDR_NONE) {
  461. bReturn=TRUE;
  462. break;
  463. }
  464. } else {
  465. // DbgPrint("IRMON: mismatch AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
  466. }
  467. CurrentAdapter=CurrentAdapter->Next;
  468. }
  469. } else {
  470. DbgPrint("irmon: GetAdaptersInfo(2) failed\n");
  471. }
  472. HeapFree(GetProcessHeap(),0,AdapterInfo);
  473. AdapterInfo=NULL;
  474. } else {
  475. DbgPrint("irmon: allocation failed\n");
  476. }
  477. return bReturn;
  478. }
  479. #endif //ip_obex