1 /*
2 * ethsock.cxx
3 *
4 * Direct Ethernet socket implementation.
5 *
6 * Portable Windows Library
7 *
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
26 *
27 * Contributor(s): ______________________________________.
28 *
29 * $Revision: 25062 $
30 * $Author: rjongbloed $
31 * $Date: 2011-01-13 22:14:36 -0600 (Thu, 13 Jan 2011) $
32 */
33
34 #include <ptlib.h>
35 #include <ptlib/sockets.h>
36
37 #include <iphlpapi.h>
38 #ifdef _MSC_VER
39 #pragma comment(lib, "iphlpapi.lib")
40 #endif
41
42
43 ///////////////////////////////////////////////////////////////////////////////
44 // Stuff from ndis.h
45
46 #define OID_802_3_PERMANENT_ADDRESS 0x01010101
47 #define OID_802_3_CURRENT_ADDRESS 0x01010102
48
49 #define OID_GEN_DRIVER_VERSION 0x00010110
50 #define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
51 #define OID_GEN_MEDIA_SUPPORTED 0x00010103
52
53 #if (WINVER <= 0x502) // These are defined in Vista SDK
54
55 #define NDIS_PACKET_TYPE_DIRECTED 0x0001
56 #define NDIS_PACKET_TYPE_MULTICAST 0x0002
57 #define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
58 #define NDIS_PACKET_TYPE_BROADCAST 0x0008
59 #define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
60
61 typedef enum _NDIS_MEDIUM {
62 NdisMedium802_3,
63 NdisMedium802_5,
64 NdisMediumFddi,
65 NdisMediumWan,
66 NdisMediumLocalTalk,
67 NdisMediumDix, // defined for convenience, not a real medium
68 NdisMediumArcnetRaw,
69 NdisMediumArcnet878_2
70 } NDIS_MEDIUM, *PNDIS_MEDIUM;
71 #endif
72
73 ///////////////////////////////////////////////////////////////////////////////
74
75
76 #define USE_VPACKET
77 #include <ptlib/msos/ptlib/epacket.h>
78
79 #define IPv6_ENABLED (P_HAS_IPV6 && (WINVER>=0x501))
80
81 #if IPv6_ENABLED
82 #include <ptlib/msos/ptlib/addrv6.h>
83 #endif
84
85 #ifdef USE_VPACKET
86 #define PACKET_SERVICE_NAME "Packet"
87 #define PACKET_VXD_NAME "VPacket"
88 #else
89 #define PACKET_SERVICE_NAME "EPacket"
90 #define PACKET_VXD_NAME "EPacket"
91 #endif
92
93 #define SERVICES_REGISTRY_KEY "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\"
94
95
96 /////////////////////////////////////////////////////////////////////////////
97
98 class PWin32OidBuffer
99 {
100 public:
101 PWin32OidBuffer(UINT oid, UINT len, const BYTE * data = NULL);
~PWin32OidBuffer()102 ~PWin32OidBuffer() { delete buffer; }
103
operator void*()104 operator void *() { return buffer; }
operator DWORD()105 operator DWORD () { return size; }
operator [](int i)106 DWORD operator [](int i) { return buffer[i]; }
107
108 void Move(BYTE * data, DWORD received);
109
110 private:
111 DWORD * buffer;
112 UINT size;
113 };
114
115
116 ///////////////////////////////////////////////////////////////////////////////
117
118 class PWin32PacketDriver
119 {
120 public:
121 static PWin32PacketDriver * Create();
122
123 virtual ~PWin32PacketDriver();
124
125 bool IsOpen() const;
126 void Close();
127 DWORD GetLastError() const;
128
129 virtual bool EnumInterfaces(PINDEX idx, PString & name) = 0;
130 virtual bool BindInterface(const PString & interfaceName) = 0;
131
132 virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask) = 0;
133
134 virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap) = 0;
135 virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap) = 0;
136 bool CompleteIO(DWORD & received, PWin32Overlapped & overlap);
137
138 bool IoControl(UINT func,
139 const void * input, DWORD inSize,
140 void * output, DWORD outSize,
141 DWORD & received);
142
143 PBoolean QueryOid(UINT oid, DWORD & data);
144 PBoolean QueryOid(UINT oid, UINT len, BYTE * data);
145 PBoolean SetOid(UINT oid, DWORD data);
146 PBoolean SetOid(UINT oid, UINT len, const BYTE * data);
GetQueryOidCommand(DWORD) const147 virtual UINT GetQueryOidCommand(DWORD /*oid*/) const { return IOCTL_EPACKET_QUERY_OID; }
148
149 protected:
150 PWin32PacketDriver();
151
152 DWORD dwError;
153 HANDLE hDriver;
154 };
155
156 ///////////////////////////////////////////////////////////////////////////////
157
158 #ifdef _WIN32_WCE
159
160 class PWin32PacketCe : public PWin32PacketDriver
161 {
162 public:
163 PWin32PacketCe();
164
165 virtual bool EnumInterfaces(PINDEX idx, PString & name);
166 virtual bool BindInterface(const PString & interfaceName);
167
168 virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
169
170 virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
171 virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
172
173 protected:
174 PStringArray ipAddresses;
175 PStringArray netMasks;
176 PStringArray interfaces;
177 };
178
179 #else // _WIN32_WCE
180
181 /////////////////////////////////////////////////////////////////////////////
182
183 class PWin32PacketVxD : public PWin32PacketDriver
184 {
185 public:
186 virtual bool EnumInterfaces(PINDEX idx, PString & name);
187 virtual bool BindInterface(const PString & interfaceName);
188
189 virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
190
191 virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
192 virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
193
194 #ifdef USE_VPACKET
GetQueryOidCommand(DWORD oid) const195 virtual UINT GetQueryOidCommand(DWORD oid) const
196 { return oid >= OID_802_3_PERMANENT_ADDRESS ? IOCTL_EPACKET_QUERY_OID : IOCTL_EPACKET_STATISTICS; }
197 #endif
198
199 protected:
200 PStringArray transportBinding;
201 };
202
203
204 ///////////////////////////////////////////////////////////////////////////////
205
206 class PWin32PacketSYS : public PWin32PacketDriver
207 {
208 public:
209 PWin32PacketSYS();
210
211 virtual bool EnumInterfaces(PINDEX idx, PString & name);
212 virtual bool BindInterface(const PString & interfaceName);
213
214 virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
215
216 virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
217 virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
218
219 protected:
220 PString registryKey;
221 };
222
223
224 #endif // _WIN32_WCE
225
226
227 ///////////////////////////////////////////////////////////////////////////////
228
229 class PWin32PacketBuffer : public PBYTEArray
230 {
231 PCLASSINFO(PWin32PacketBuffer, PBYTEArray)
232 public:
233 enum Statuses {
234 Uninitialised,
235 Progressing,
236 Completed
237 };
238
239 PWin32PacketBuffer(PINDEX sz);
240
241 PINDEX GetData(void * buf, PINDEX size);
242 PINDEX PutData(const void * buf, PINDEX length);
GetEvent() const243 HANDLE GetEvent() const { return overlap.hEvent; }
244
245 bool ReadAsync(PWin32PacketDriver & pkt);
246 bool ReadComplete(PWin32PacketDriver & pkt);
247 bool WriteAsync(PWin32PacketDriver & pkt);
248 bool WriteComplete(PWin32PacketDriver & pkt);
249
InProgress() const250 bool InProgress() const { return status == Progressing; }
IsCompleted() const251 bool IsCompleted() const { return status == Completed; }
252 bool IsType(WORD type) const;
253
254 protected:
255 Statuses status;
256 PWin32Overlapped overlap;
257 DWORD count;
258 };
259
260
261 #define new PNEW
262
263
264 /////////////////////////////////////////////////////////////////////////////
265
PWin32OidBuffer(UINT oid,UINT len,const BYTE * data)266 PWin32OidBuffer::PWin32OidBuffer(UINT oid, UINT len, const BYTE * data)
267 {
268 size = sizeof(DWORD)*2 + len;
269 buffer = new DWORD[(size+sizeof(DWORD)-1)/sizeof(DWORD)];
270
271 buffer[0] = oid;
272 buffer[1] = len;
273 if (data != NULL)
274 memcpy(&buffer[2], data, len);
275 }
276
277
Move(BYTE * data,DWORD received)278 void PWin32OidBuffer::Move(BYTE * data, DWORD received)
279 {
280 memcpy(data, &buffer[2], received-sizeof(DWORD)*2);
281 }
282
283
284 ///////////////////////////////////////////////////////////////////////////////
285
Create()286 PWin32PacketDriver * PWin32PacketDriver::Create()
287 {
288 OSVERSIONINFO info;
289 info.dwOSVersionInfoSize = sizeof(info);
290 GetVersionEx(&info);
291 #ifdef _WIN32_WCE
292 return new PWin32PacketCe;
293 #else // _WIN32_WCE
294 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
295 return new PWin32PacketSYS;
296 else
297 return new PWin32PacketVxD;
298 #endif // _WIN32_WCE
299 }
300
301
PWin32PacketDriver()302 PWin32PacketDriver::PWin32PacketDriver()
303 {
304 hDriver = INVALID_HANDLE_VALUE;
305 dwError = ERROR_OPEN_FAILED;
306 }
307
308
~PWin32PacketDriver()309 PWin32PacketDriver::~PWin32PacketDriver()
310 {
311 Close();
312 }
313
314
Close()315 void PWin32PacketDriver::Close()
316 {
317 if (hDriver != INVALID_HANDLE_VALUE) {
318 CloseHandle(hDriver);
319 hDriver = INVALID_HANDLE_VALUE;
320 }
321 }
322
323
IsOpen() const324 bool PWin32PacketDriver::IsOpen() const
325 {
326 return hDriver != INVALID_HANDLE_VALUE;
327 }
328
329
GetLastError() const330 DWORD PWin32PacketDriver::GetLastError() const
331 {
332 return dwError;
333 }
334
335
IoControl(UINT func,const void * input,DWORD inSize,void * output,DWORD outSize,DWORD & received)336 bool PWin32PacketDriver::IoControl(UINT func,
337 const void * input, DWORD inSize,
338 void * output, DWORD outSize, DWORD & received)
339 {
340 PWin32Overlapped overlap;
341
342 if (DeviceIoControl(hDriver, func,
343 (LPVOID)input, inSize, output, outSize,
344 &received, &overlap)) {
345 dwError = ERROR_SUCCESS;
346 return true;
347 }
348
349 dwError = ::GetLastError();
350 if (dwError != ERROR_IO_PENDING)
351 return false;
352
353 return CompleteIO(received, overlap);
354 }
355
356 #ifdef _WIN32_WCE
CompleteIO(DWORD &,PWin32Overlapped &)357 bool PWin32PacketDriver::CompleteIO(DWORD &, PWin32Overlapped &)
358 {
359 return true;
360 }
361 #else
CompleteIO(DWORD & received,PWin32Overlapped & overlap)362 bool PWin32PacketDriver::CompleteIO(DWORD & received, PWin32Overlapped & overlap)
363 {
364 received = 0;
365 if (GetOverlappedResult(hDriver, &overlap, &received, true)) {
366 dwError = ERROR_SUCCESS;
367 return true;
368 }
369
370 dwError = ::GetLastError();
371 return false;
372 }
373 #endif
374
375
QueryOid(UINT oid,UINT len,BYTE * data)376 PBoolean PWin32PacketDriver::QueryOid(UINT oid, UINT len, BYTE * data)
377 {
378 PWin32OidBuffer buf(oid, len);
379 DWORD rxsize = 0;
380 if (!IoControl(GetQueryOidCommand(oid), buf, buf, buf, buf, rxsize))
381 return PFalse;
382
383 if (rxsize == 0)
384 return PFalse;
385
386 buf.Move(data, rxsize);
387 return PTrue;
388 }
389
390
QueryOid(UINT oid,DWORD & data)391 PBoolean PWin32PacketDriver::QueryOid(UINT oid, DWORD & data)
392 {
393 DWORD oidData[3];
394 oidData[0] = oid;
395 oidData[1] = sizeof(data);
396 oidData[2] = 0x12345678;
397
398 DWORD rxsize = 0;
399 if (!IoControl(GetQueryOidCommand(oid),
400 oidData, sizeof(oidData),
401 oidData, sizeof(oidData),
402 rxsize))
403 return PFalse;
404
405 if (rxsize == 0)
406 return PFalse;
407
408 data = oidData[2];
409 return PTrue;
410 }
411
412
SetOid(UINT oid,UINT len,const BYTE * data)413 PBoolean PWin32PacketDriver::SetOid(UINT oid, UINT len, const BYTE * data)
414 {
415 DWORD rxsize = 0;
416 PWin32OidBuffer buf(oid, len, data);
417 return IoControl(IOCTL_EPACKET_SET_OID, buf, buf, buf, buf, rxsize);
418 }
419
420
SetOid(UINT oid,DWORD data)421 PBoolean PWin32PacketDriver::SetOid(UINT oid, DWORD data)
422 {
423 DWORD oidData[3];
424 oidData[0] = oid;
425 oidData[1] = sizeof(data);
426 oidData[2] = data;
427 DWORD rxsize;
428 return IoControl(IOCTL_EPACKET_SET_OID,
429 oidData, sizeof(oidData), oidData, sizeof(oidData), rxsize);
430 }
431
432
433 ///////////////////////////////////////////////////////////////////////////////
434
435 #ifdef _WIN32_WCE
436
PWin32PacketCe()437 PWin32PacketCe::PWin32PacketCe()
438 {
439 PString str, driver, nameStr, keyStr, driverStr, miniportStr, linkageStr, routeStr, tcpipStr;
440
441 static const PString ActiveDrivers = "HKEY_LOCAL_MACHINE\\Drivers\\Active";
442 static const PString CommBase = "HKEY_LOCAL_MACHINE\\Comm";
443
444 // Collecting active drivers
445 RegistryKey registry(ActiveDrivers, RegistryKey::ReadOnly);
446 for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++)
447 {
448 driver = ActiveDrivers + "\\" + str;
449 RegistryKey driverKey( driver, RegistryKey::ReadOnly );
450
451 // Filter out non - NDS drivers
452 if (!driverKey.QueryValue( "Name", nameStr ) || nameStr.Find("NDS") == P_MAX_INDEX )
453 continue;
454
455 // Active network driver found
456 //
457 // e.g. built-in driver has "Key" = Drivers\BuiltIn\NDIS
458 if( driverKey.QueryValue( "Key", keyStr ) )
459 {
460 if( P_MAX_INDEX != keyStr.Find("BuiltIn") )
461 {
462 // Built-in driver case
463 continue;
464 }
465 else
466 {
467 driverStr = "HKEY_LOCAL_MACHINE\\"+ keyStr;
468 RegistryKey ActiveDriverKey( driverStr, RegistryKey::ReadOnly );
469
470 // Get miniport value
471 if( ActiveDriverKey.QueryValue( "Miniport", miniportStr ) )
472 {
473 // Get miniport linkage
474 //
475 // e.g. [HKEY_LOCAL_MACHINE\Comm\SOCKETLPE\Linkage]
476 linkageStr = CommBase + "\\" + miniportStr + "\\Linkage";
477
478 RegistryKey LinkageKey( linkageStr, RegistryKey::ReadOnly );
479
480 // Get route to real driver
481 if( LinkageKey.QueryValue( "Route", routeStr ) )
482 {
483 tcpipStr = CommBase + "\\" + routeStr + "\\Parms\\TcpIp";
484
485 RegistryKey TcpIpKey( tcpipStr, RegistryKey::ReadOnly );
486
487 DWORD dwDHCPEnabled = false;
488 TcpIpKey.QueryValue( "EnableDHCP", dwDHCPEnabled, true );
489
490 /// Collect IP addresses and net masks
491 PString ipAddress, netMask;
492 if ( !dwDHCPEnabled )
493 {
494 if (TcpIpKey.QueryValue( "IpAddress", ipAddress )
495 && (ipAddress != "0.0.0.0") )
496 {
497 interfaces[interfaces.GetSize()] = tcpipStr; // Registry key for the driver
498 ipAddresses[ipAddresses.GetSize()] = ipAddress; // It's IP
499 if( driverKey.QueryValue( "Subnetmask", netMask ) )
500 netMasks[netMasks.GetSize()] = netMask; // It's mask
501 else
502 netMasks[netMasks.GetSize()] = "255.255.255.0";
503 }
504 }
505 else // DHCP enabled
506 if( TcpIpKey.QueryValue( "DhcpIpAddress", ipAddress )
507 && (ipAddress != "0.0.0.0") )
508 {
509 interfaces[interfaces.GetSize()] = str;
510 ipAddresses[ipAddresses.GetSize()] = ipAddress;
511 if( driverKey.QueryValue( "DhcpSubnetMask", netMask ) )
512 netMasks[netMasks.GetSize()] = netMask;
513 else
514 netMasks[netMasks.GetSize()] = "255.255.255.0";
515 }
516 }
517 }
518 }
519 }
520 }
521 }
522
EnumInterfaces(PINDEX idx,PString & name)523 bool PWin32PacketCe::EnumInterfaces(PINDEX idx, PString & name)
524 {
525 if( idx >= interfaces.GetSize() )
526 return false;
527
528 name = interfaces[idx];
529 return true;
530 }
531
532
BindInterface(const PString &)533 bool PWin32PacketCe::BindInterface(const PString &)
534 {
535 return true;
536 }
537
538
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)539 bool PWin32PacketCe::EnumIpAddress(PINDEX idx,
540 PIPSocket::Address & addr,
541 PIPSocket::Address & net_mask)
542 {
543 if( idx >= interfaces.GetSize() )
544 return false;
545
546 addr = ipAddresses[idx];
547 net_mask = netMasks[idx];
548 return true;
549 }
550
551
BeginRead(void *,DWORD,DWORD &,PWin32Overlapped &)552 bool PWin32PacketCe::BeginRead(void *, DWORD, DWORD & , PWin32Overlapped &)
553 {
554 return true;
555 }
556
557
BeginWrite(const void *,DWORD,PWin32Overlapped &)558 bool PWin32PacketCe::BeginWrite(const void *, DWORD, PWin32Overlapped &)
559 {
560 return true;
561 }
562
563 #else // _WIN32_WCE
564
565 ///////////////////////////////////////////////////////////////////////////////
566
EnumInterfaces(PINDEX idx,PString & name)567 bool PWin32PacketVxD::EnumInterfaces(PINDEX idx, PString & name)
568 {
569 static const PString RegBase = SERVICES_REGISTRY_KEY "Class\\Net";
570
571 PString keyName;
572 RegistryKey registry(RegBase, RegistryKey::ReadOnly);
573 if (!registry.EnumKey(idx, keyName))
574 return false;
575
576 PString description;
577 RegistryKey subkey(RegBase + "\\" + keyName, RegistryKey::ReadOnly);
578 if (subkey.QueryValue("DriverDesc", description))
579 name = keyName + ": " + description;
580 else
581 name = keyName;
582
583 return true;
584 }
585
586
SearchRegistryKeys(const PString & key,const PString & variable,const PString & value)587 static PString SearchRegistryKeys(const PString & key,
588 const PString & variable,
589 const PString & value)
590 {
591 RegistryKey registry(key, RegistryKey::ReadOnly);
592
593 PString str;
594 if (registry.QueryValue(variable, str) && (str *= value))
595 return key;
596
597 for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++) {
598 PString result = SearchRegistryKeys(key + str + '\\', variable, value);
599 if (!result)
600 return result;
601 }
602
603 return PString::Empty();
604 }
605
606
BindInterface(const PString & interfaceName)607 bool PWin32PacketVxD::BindInterface(const PString & interfaceName)
608 {
609 BYTE buf[20];
610 DWORD rxsize;
611
612 if (hDriver == INVALID_HANDLE_VALUE) {
613 hDriver = CreateFile("\\\\.\\" PACKET_VXD_NAME ".VXD",
614 GENERIC_READ | GENERIC_WRITE,
615 0,
616 NULL,
617 OPEN_EXISTING,
618 FILE_ATTRIBUTE_NORMAL |
619 FILE_FLAG_OVERLAPPED |
620 FILE_FLAG_DELETE_ON_CLOSE,
621 NULL);
622 if (hDriver == INVALID_HANDLE_VALUE) {
623 dwError = ::GetLastError();
624 return false;
625 }
626
627 #ifndef USE_VPACKET
628 rxsize = 0;
629 if (!IoControl(IOCTL_EPACKET_VERSION, NULL, 0, buf, sizeof(buf), rxsize)) {
630 dwError = ::GetLastError();
631 return false;
632 }
633
634 if (rxsize != 2 || buf[0] < 1 || buf[1] < 1) { // Require driver version 1.1
635 Close();
636 dwError = ERROR_BAD_DRIVER;
637 return false;
638 }
639 #endif
640 }
641
642 PString devName;
643 PINDEX colon = interfaceName.Find(':');
644 if (colon != P_MAX_INDEX)
645 devName = interfaceName.Left(colon);
646 else
647 devName = interfaceName;
648
649 rxsize = 0;
650 if (!IoControl(IOCTL_EPACKET_BIND,
651 (const char *)devName, devName.GetLength()+1,
652 buf, sizeof(buf), rxsize) || rxsize == 0) {
653 dwError = ::GetLastError();
654 if (dwError == 0)
655 dwError = ERROR_BAD_DRIVER;
656 return false;
657 }
658
659 // Get a random OID to verify that the driver did actually open
660 if (!QueryOid(OID_GEN_DRIVER_VERSION, 2, buf))
661 return false;
662
663 dwError = ERROR_SUCCESS; // Successful, even if may not be bound.
664
665 PString devKey = SearchRegistryKeys("HKEY_LOCAL_MACHINE\\Enum\\", "Driver", "Net\\" + devName);
666 if (devKey.IsEmpty())
667 return true;
668
669 RegistryKey bindRegistry(devKey + "Bindings", RegistryKey::ReadOnly);
670 PString binding;
671 PINDEX idx = 0;
672 while (bindRegistry.EnumValue(idx++, binding)) {
673 if (binding.Left(6) *= "MSTCP\\") {
674 RegistryKey mstcpRegistry("HKEY_LOCAL_MACHINE\\Enum\\Network\\" + binding, RegistryKey::ReadOnly);
675 PString str;
676 if (mstcpRegistry.QueryValue("Driver", str))
677 transportBinding.AppendString(SERVICES_REGISTRY_KEY "Class\\" + str);
678 }
679 }
680 return true;
681 }
682
683
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)684 bool PWin32PacketVxD::EnumIpAddress(PINDEX idx,
685 PIPSocket::Address & addr,
686 PIPSocket::Address & net_mask)
687 {
688 if (idx >= transportBinding.GetSize())
689 return false;
690
691 RegistryKey transportRegistry(transportBinding[idx], RegistryKey::ReadOnly);
692 PString str;
693 if (transportRegistry.QueryValue("IPAddress", str))
694 addr = str;
695 else
696 addr = 0;
697
698 if (addr != 0) {
699 if (addr.GetVersion() == 6) {
700 net_mask = 0;
701 // Seb: Something to do ?
702 } else {
703 if (transportRegistry.QueryValue("IPMask", str))
704 net_mask = str;
705 else {
706 if (IN_CLASSA(addr))
707 net_mask = "255.0.0.0";
708 else if (IN_CLASSB(addr))
709 net_mask = "255.255.0.0";
710 else if (IN_CLASSC(addr))
711 net_mask = "255.255.255.0";
712 else
713 net_mask = 0;
714 }
715 }
716 return true;
717 }
718
719 PEthSocket::Address macAddress;
720 if (!QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(macAddress), macAddress.b))
721 return false;
722
723 PINDEX dhcpCount;
724 for (dhcpCount = 0; dhcpCount < 8; dhcpCount++) {
725 RegistryKey dhcpRegistry(psprintf(SERVICES_REGISTRY_KEY "VxD\\DHCP\\DhcpInfo%02u", dhcpCount),
726 RegistryKey::ReadOnly);
727 if (dhcpRegistry.QueryValue("DhcpInfo", str)) {
728 struct DhcpInfo {
729 DWORD index;
730 PIPSocket::Address ipAddress;
731 PIPSocket::Address mask;
732 PIPSocket::Address server;
733 PIPSocket::Address anotherAddress;
734 DWORD unknown1;
735 DWORD unknown2;
736 DWORD unknown3;
737 DWORD unknown4;
738 DWORD unknown5;
739 DWORD unknown6;
740 BYTE unknown7;
741 PEthSocket::Address macAddress;
742 } * dhcpInfo = (DhcpInfo *)(const char *)str;
743 if (dhcpInfo->macAddress == macAddress) {
744 addr = dhcpInfo->ipAddress;
745 net_mask = dhcpInfo->mask;
746 return true;
747 }
748 }
749 else if (dhcpRegistry.QueryValue("HardwareAddress", str) &&
750 str.GetSize() >= sizeof(PEthSocket::Address)) {
751 PEthSocket::Address hardwareAddress;
752 memcpy(&hardwareAddress, (const char *)str, sizeof(hardwareAddress));
753 if (hardwareAddress == macAddress) {
754 if (dhcpRegistry.QueryValue("DhcpIPAddress", str) &&
755 str.GetSize() >= sizeof(addr)) {
756 memcpy(&addr, (const char *)str, sizeof(addr));
757 if (dhcpRegistry.QueryValue("DhcpSubnetMask", str) &&
758 str.GetSize() >= sizeof(net_mask)) {
759 memcpy(&net_mask, (const char *)str, sizeof(net_mask));
760 return true;
761 }
762 }
763 }
764 }
765 }
766
767 return false;
768 }
769
770
BeginRead(void * buf,DWORD size,DWORD & received,PWin32Overlapped & overlap)771 bool PWin32PacketVxD::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
772 {
773 received = 0;
774 if (DeviceIoControl(hDriver, IOCTL_EPACKET_READ,
775 buf, size, buf, size, &received, &overlap)) {
776 dwError = ERROR_SUCCESS;
777 return true;
778 }
779
780 dwError = ::GetLastError();
781 return dwError == ERROR_IO_PENDING;
782 }
783
784
BeginWrite(const void * buf,DWORD len,PWin32Overlapped & overlap)785 bool PWin32PacketVxD::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
786 {
787 DWORD rxsize = 0;
788 BYTE dummy[2];
789 if (DeviceIoControl(hDriver, IOCTL_EPACKET_WRITE,
790 (void *)buf, len, dummy, sizeof(dummy), &rxsize, &overlap)) {
791 dwError = ERROR_SUCCESS;
792 return true;
793 }
794
795 dwError = ::GetLastError();
796 return dwError == ERROR_IO_PENDING;
797 }
798
799
800 ///////////////////////////////////////////////////////////////////////////////
801
RegistryQueryMultiSz(RegistryKey & registry,const PString & variable,PINDEX idx,PString & value)802 static bool RegistryQueryMultiSz(RegistryKey & registry,
803 const PString & variable,
804 PINDEX idx,
805 PString & value)
806 {
807 PString allValues;
808 if (!registry.QueryValue(variable, allValues))
809 return PFalse;
810
811 const char * ptr = allValues;
812 while (*ptr != '\0' && idx-- > 0)
813 ptr += strlen(ptr)+1;
814
815 if (*ptr == '\0')
816 return PFalse;
817
818 value = ptr;
819 return PTrue;
820 }
821
822 ///////////////////////////////////////////////////////////////////////////////
823
PWin32PacketSYS()824 PWin32PacketSYS::PWin32PacketSYS()
825 {
826 // Start the packet driver service
827 SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
828 if (hManager != NULL) {
829 SC_HANDLE hService = OpenService(hManager, PACKET_SERVICE_NAME, SERVICE_START);
830 if (hService != NULL) {
831 StartService(hService, 0, NULL);
832 dwError = ::GetLastError();
833 CloseServiceHandle(hService);
834 }
835 CloseServiceHandle(hManager);
836 }
837 }
838
839
840 static const char PacketDeviceStr[] = "\\Device\\" PACKET_SERVICE_NAME "_";
841
EnumInterfaces(PINDEX idx,PString & name)842 bool PWin32PacketSYS::EnumInterfaces(PINDEX idx, PString & name)
843 {
844 RegistryKey registry(SERVICES_REGISTRY_KEY PACKET_SERVICE_NAME "\\Linkage",
845 RegistryKey::ReadOnly);
846 if (!RegistryQueryMultiSz(registry, "Export", idx, name)) {
847 dwError = ERROR_NO_MORE_ITEMS;
848 return false;
849 }
850
851 if (strncasecmp(name, PacketDeviceStr, sizeof(PacketDeviceStr)-1) == 0)
852 name.Delete(0, sizeof(PacketDeviceStr)-1);
853
854 return true;
855 }
856
857
BindInterface(const PString & interfaceName)858 bool PWin32PacketSYS::BindInterface(const PString & interfaceName)
859 {
860 Close();
861
862 if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
863 PACKET_SERVICE_NAME "_" + interfaceName,
864 PacketDeviceStr + interfaceName)) {
865 dwError = ::GetLastError();
866 return false;
867 }
868
869 ::SetLastError(0);
870 hDriver = CreateFile("\\\\.\\" PACKET_SERVICE_NAME "_" + interfaceName,
871 GENERIC_READ | GENERIC_WRITE,
872 0,
873 NULL,
874 CREATE_ALWAYS,
875 FILE_FLAG_OVERLAPPED,
876 NULL);
877 if (hDriver == INVALID_HANDLE_VALUE) {
878 dwError = ::GetLastError();
879 return false;
880 }
881
882 registryKey = SERVICES_REGISTRY_KEY + interfaceName + "\\Parameters\\Tcpip";
883 dwError = ERROR_SUCCESS;
884
885 return true;
886 }
887
888
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)889 bool PWin32PacketSYS::EnumIpAddress(PINDEX idx,
890 PIPSocket::Address & addr,
891 PIPSocket::Address & net_mask)
892 {
893 PString str;
894 RegistryKey registry(registryKey, RegistryKey::ReadOnly);
895
896 if (!RegistryQueryMultiSz(registry, "IPAddress", idx, str)) {
897 dwError = ERROR_NO_MORE_ITEMS;
898 return false;
899 }
900 addr = str;
901
902 if (!RegistryQueryMultiSz(registry, "SubnetMask", idx, str)) {
903 dwError = ERROR_NO_MORE_ITEMS;
904 return false;
905 }
906 net_mask = str;
907
908 return true;
909 }
910
911
BeginRead(void * buf,DWORD size,DWORD & received,PWin32Overlapped & overlap)912 bool PWin32PacketSYS::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
913 {
914 overlap.Reset();
915 received = 0;
916
917 if (ReadFile(hDriver, buf, size, &received, &overlap)) {
918 dwError = ERROR_SUCCESS;
919 return true;
920 }
921
922 return (dwError = ::GetLastError()) == ERROR_IO_PENDING;
923 }
924
925
BeginWrite(const void * buf,DWORD len,PWin32Overlapped & overlap)926 bool PWin32PacketSYS::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
927 {
928 overlap.Reset();
929 DWORD sent = 0;
930 if (WriteFile(hDriver, buf, len, &sent, &overlap)) {
931 dwError = ERROR_SUCCESS;
932 return true;
933 }
934
935 dwError = ::GetLastError();
936 return dwError == ERROR_IO_PENDING;
937 }
938
939
940 #endif // !_WIN32_WCE
941
942 ///////////////////////////////////////////////////////////////////////////////
943
PEthSocket(PINDEX nReadBuffers,PINDEX nWriteBuffers,PINDEX size)944 PEthSocket::PEthSocket(PINDEX nReadBuffers, PINDEX nWriteBuffers, PINDEX size)
945 : readBuffers(min(nReadBuffers, MAXIMUM_WAIT_OBJECTS)),
946 writeBuffers(min(nWriteBuffers, MAXIMUM_WAIT_OBJECTS))
947 {
948 driver = PWin32PacketDriver::Create();
949 PINDEX i;
950 for (i = 0; i < nReadBuffers; i++)
951 readBuffers.SetAt(i, new PWin32PacketBuffer(size));
952 for (i = 0; i < nWriteBuffers; i++)
953 writeBuffers.SetAt(i, new PWin32PacketBuffer(size));
954
955 filterType = TypeAll;
956 }
957
958
~PEthSocket()959 PEthSocket::~PEthSocket()
960 {
961 Close();
962
963 delete driver;
964 }
965
966
OpenSocket()967 PBoolean PEthSocket::OpenSocket()
968 {
969 PAssertAlways(PUnimplementedFunction);
970 return false;
971 }
972
973
Close()974 PBoolean PEthSocket::Close()
975 {
976 driver->Close();
977 os_handle = -1;
978 return true;
979 }
980
981
GetName() const982 PString PEthSocket::GetName() const
983 {
984 return interfaceName;
985 }
986
987
Connect(const PString & newName)988 PBoolean PEthSocket::Connect(const PString & newName)
989 {
990 Close();
991
992 if (!driver->BindInterface(newName))
993 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
994
995 interfaceName = newName;
996 os_handle = 1;
997 return true;
998 }
999
1000
EnumInterfaces(PINDEX idx,PString & name)1001 PBoolean PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
1002 {
1003 return driver->EnumInterfaces(idx, name);
1004 }
1005
1006
GetAddress(Address & addr)1007 PBoolean PEthSocket::GetAddress(Address & addr)
1008 {
1009 if (driver->QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(addr), addr.b))
1010 return true;
1011
1012 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1013 }
1014
1015
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)1016 PBoolean PEthSocket::EnumIpAddress(PINDEX idx,
1017 PIPSocket::Address & addr,
1018 PIPSocket::Address & net_mask)
1019 {
1020 if (IsOpen()) {
1021 if (driver->EnumIpAddress(idx, addr, net_mask))
1022 return true;
1023
1024 return SetErrorValues(NotFound, ENOENT);
1025 }
1026
1027 return SetErrorValues(NotOpen, EBADF);
1028 }
1029
1030
1031 static const struct {
1032 unsigned pwlib;
1033 DWORD ndis;
1034 } FilterMasks[] = {
1035 { PEthSocket::FilterDirected, NDIS_PACKET_TYPE_DIRECTED },
1036 { PEthSocket::FilterMulticast, NDIS_PACKET_TYPE_MULTICAST },
1037 { PEthSocket::FilterAllMulticast, NDIS_PACKET_TYPE_ALL_MULTICAST },
1038 { PEthSocket::FilterBroadcast, NDIS_PACKET_TYPE_BROADCAST },
1039 { PEthSocket::FilterPromiscuous, NDIS_PACKET_TYPE_PROMISCUOUS }
1040 };
1041
1042
GetFilter(unsigned & mask,WORD & type)1043 PBoolean PEthSocket::GetFilter(unsigned & mask, WORD & type)
1044 {
1045 if (!IsOpen())
1046 return SetErrorValues(NotOpen, EBADF);
1047
1048 DWORD filter = 0;
1049 if (!driver->QueryOid(OID_GEN_CURRENT_PACKET_FILTER, filter))
1050 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1051
1052 if (filter == 0)
1053 return PEthSocket::FilterDirected;
1054
1055 mask = 0;
1056 for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
1057 if ((filter&FilterMasks[i].ndis) != 0)
1058 mask |= FilterMasks[i].pwlib;
1059 }
1060
1061 type = (WORD)filterType;
1062 return true;
1063 }
1064
1065
SetFilter(unsigned filter,WORD type)1066 PBoolean PEthSocket::SetFilter(unsigned filter, WORD type)
1067 {
1068 if (!IsOpen())
1069 return SetErrorValues(NotOpen, EBADF);
1070
1071 DWORD bits = 0;
1072 for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
1073 if ((filter&FilterMasks[i].pwlib) != 0)
1074 bits |= FilterMasks[i].ndis;
1075 }
1076
1077 if (!driver->SetOid(OID_GEN_CURRENT_PACKET_FILTER, bits))
1078 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1079
1080 filterType = type;
1081 return true;
1082 }
1083
1084
GetMedium()1085 PEthSocket::MediumTypes PEthSocket::GetMedium()
1086 {
1087 if (!IsOpen()) {
1088 SetErrorValues(NotOpen, EBADF);
1089 return NumMediumTypes;
1090 }
1091
1092 DWORD medium = 0xffffffff;
1093 if (!driver->QueryOid(OID_GEN_MEDIA_SUPPORTED, medium) || medium == 0xffffffff) {
1094 SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1095 return NumMediumTypes;
1096 }
1097
1098 static const DWORD MediumValues[NumMediumTypes] = {
1099 0xffffffff, NdisMedium802_3, NdisMediumWan, 0xffffffff
1100 };
1101
1102 for (int type = Medium802_3; type < NumMediumTypes; type++) {
1103 if (MediumValues[type] == medium)
1104 return (MediumTypes)type;
1105 }
1106
1107 return MediumUnknown;
1108 }
1109
1110
Read(void * data,PINDEX length)1111 PBoolean PEthSocket::Read(void * data, PINDEX length)
1112 {
1113 if (!IsOpen())
1114 return SetErrorValues(NotOpen, EBADF, LastReadError);
1115
1116 PINDEX idx;
1117 PINDEX numBuffers = readBuffers.GetSize();
1118
1119 do {
1120 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1121
1122 for (idx = 0; idx < numBuffers; idx++) {
1123 PWin32PacketBuffer & buffer = readBuffers[idx];
1124 if (buffer.InProgress()) {
1125 if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
1126 if (!buffer.ReadComplete(*driver))
1127 return ConvertOSError(-1, LastReadError);
1128 }
1129 else {
1130 if (!buffer.ReadAsync(*driver))
1131 return ConvertOSError(-1, LastReadError);
1132 }
1133
1134 if (buffer.IsCompleted() && buffer.IsType(filterType)) {
1135 lastReadCount = buffer.GetData(data, length);
1136 return true;
1137 }
1138
1139 handles[idx] = buffer.GetEvent();
1140 }
1141
1142 DWORD result;
1143 PINDEX retries = 100;
1144 for (;;) {
1145 result = WaitForMultipleObjects(numBuffers, handles, false, INFINITE);
1146 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + (DWORD)numBuffers)
1147 break;
1148
1149 if (::GetLastError() != ERROR_INVALID_HANDLE || retries == 0)
1150 return ConvertOSError(-1, LastReadError);
1151
1152 retries--;
1153 }
1154
1155 idx = result - WAIT_OBJECT_0;
1156 if (!readBuffers[idx].ReadComplete(*driver))
1157 return ConvertOSError(-1, LastReadError);
1158
1159 } while (!readBuffers[idx].IsType(filterType));
1160
1161 lastReadCount = readBuffers[idx].GetData(data, length);
1162 return true;
1163 }
1164
1165
Write(const void * data,PINDEX length)1166 PBoolean PEthSocket::Write(const void * data, PINDEX length)
1167 {
1168 if (!IsOpen())
1169 return SetErrorValues(NotOpen, EBADF, LastWriteError);
1170
1171 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1172 PINDEX numBuffers = writeBuffers.GetSize();
1173
1174 PINDEX idx;
1175 for (idx = 0; idx < numBuffers; idx++) {
1176 PWin32PacketBuffer & buffer = writeBuffers[idx];
1177 if (buffer.InProgress()) {
1178 if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
1179 if (!buffer.WriteComplete(*driver))
1180 return ConvertOSError(-1, LastWriteError);
1181 }
1182
1183 if (!buffer.InProgress()) {
1184 lastWriteCount = buffer.PutData(data, length);
1185 return ConvertOSError(buffer.WriteAsync(*driver) ? 0 : -1, LastWriteError);
1186 }
1187
1188 handles[idx] = buffer.GetEvent();
1189 }
1190
1191 DWORD result = WaitForMultipleObjects(numBuffers, handles, false, INFINITE);
1192 if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0 + (DWORD) numBuffers)
1193 return ConvertOSError(-1, LastWriteError);
1194
1195 idx = result - WAIT_OBJECT_0;
1196 if (!writeBuffers[idx].WriteComplete(*driver))
1197 return ConvertOSError(-1, LastWriteError);
1198
1199 lastWriteCount = writeBuffers[idx].PutData(data, length);
1200 return ConvertOSError(writeBuffers[idx].WriteAsync(*driver) ? 0 : -1, LastWriteError);
1201 }
1202
1203
1204 ///////////////////////////////////////////////////////////////////////////////
1205
PWin32PacketBuffer(PINDEX sz)1206 PWin32PacketBuffer::PWin32PacketBuffer(PINDEX sz)
1207 : PBYTEArray(sz)
1208 {
1209 status = Uninitialised;
1210 count = 0;
1211 }
1212
1213
GetData(void * buf,PINDEX size)1214 PINDEX PWin32PacketBuffer::GetData(void * buf, PINDEX size)
1215 {
1216 if (count > (DWORD)size)
1217 count = size;
1218
1219 memcpy(buf, theArray, count);
1220
1221 return count;
1222 }
1223
1224
PutData(const void * buf,PINDEX length)1225 PINDEX PWin32PacketBuffer::PutData(const void * buf, PINDEX length)
1226 {
1227 count = min(GetSize(), length);
1228
1229 memcpy(theArray, buf, count);
1230
1231 return count;
1232 }
1233
1234
ReadAsync(PWin32PacketDriver & pkt)1235 PBoolean PWin32PacketBuffer::ReadAsync(PWin32PacketDriver & pkt)
1236 {
1237 if (status == Progressing)
1238 return false;
1239
1240 status = Uninitialised;
1241 if (!pkt.BeginRead(theArray, GetSize(), count, overlap))
1242 return false;
1243
1244 if (pkt.GetLastError() == ERROR_SUCCESS)
1245 status = Completed;
1246 else
1247 status = Progressing;
1248 return true;
1249 }
1250
1251
ReadComplete(PWin32PacketDriver & pkt)1252 PBoolean PWin32PacketBuffer::ReadComplete(PWin32PacketDriver & pkt)
1253 {
1254 if (status != Progressing)
1255 return status == Completed;
1256
1257 if (!pkt.CompleteIO(count, overlap)) {
1258 status = Uninitialised;
1259 return false;
1260 }
1261
1262 status = Completed;
1263 return true;
1264 }
1265
1266
WriteAsync(PWin32PacketDriver & pkt)1267 PBoolean PWin32PacketBuffer::WriteAsync(PWin32PacketDriver & pkt)
1268 {
1269 if (status == Progressing)
1270 return false;
1271
1272 status = Uninitialised;
1273 if (!pkt.BeginWrite(theArray, count, overlap))
1274 return false;
1275
1276 if (pkt.GetLastError() == ERROR_SUCCESS)
1277 status = Completed;
1278 else
1279 status = Progressing;
1280 return true;
1281 }
1282
1283
WriteComplete(PWin32PacketDriver & pkt)1284 PBoolean PWin32PacketBuffer::WriteComplete(PWin32PacketDriver & pkt)
1285 {
1286 if (status != Progressing)
1287 return status == Completed;
1288
1289 DWORD dummy;
1290 if (pkt.CompleteIO(dummy, overlap)) {
1291 status = Completed;
1292 return true;
1293 }
1294
1295 status = Uninitialised;
1296 return false;
1297 }
1298
1299
IsType(WORD filterType) const1300 PBoolean PWin32PacketBuffer::IsType(WORD filterType) const
1301 {
1302 if (filterType == PEthSocket::TypeAll)
1303 return true;
1304
1305 const PEthSocket::Frame * frame = (const PEthSocket::Frame *)theArray;
1306
1307 WORD len_or_type = ntohs(frame->snap.length);
1308 if (len_or_type > sizeof(*frame))
1309 return len_or_type == filterType;
1310
1311 if (frame->snap.dsap == 0xaa && frame->snap.ssap == 0xaa)
1312 return ntohs(frame->snap.type) == filterType; // SNAP header
1313
1314 if (frame->snap.dsap == 0xff && frame->snap.ssap == 0xff)
1315 return PEthSocket::TypeIPX == filterType; // Special case for Novell netware's stuffed up 802.3
1316
1317 if (frame->snap.dsap == 0xe0 && frame->snap.ssap == 0xe0)
1318 return PEthSocket::TypeIPX == filterType; // Special case for Novell netware's 802.2
1319
1320 return frame->snap.dsap == filterType; // A pure 802.2 protocol id
1321 }
1322
1323 ///////////////////////////////////////////////////////////////////////////////
1324
1325 class PIPRouteTable
1326 {
1327 public:
PIPRouteTable()1328 PIPRouteTable()
1329 {
1330 ULONG size = 0;
1331 DWORD error = GetIpForwardTable(NULL, &size, TRUE);
1332 if (error == ERROR_INSUFFICIENT_BUFFER && buffer.SetSize(size))
1333 error = GetIpForwardTable((MIB_IPFORWARDTABLE *)buffer.GetPointer(), &size, TRUE);
1334 if (error != NO_ERROR) {
1335 buffer.SetSize(0);
1336 buffer.SetSize(sizeof(MIB_IPFORWARDTABLE)); // So ->dwNumEntries returns zero
1337 }
1338 }
1339
Ptr() const1340 const MIB_IPFORWARDTABLE * Ptr() const { return (const MIB_IPFORWARDTABLE *)(const BYTE *)buffer; }
operator ->() const1341 const MIB_IPFORWARDTABLE * operator->() const { return Ptr(); }
operator *() const1342 const MIB_IPFORWARDTABLE & operator *() const { return *Ptr(); }
operator const MIB_IPFORWARDTABLE*() const1343 operator const MIB_IPFORWARDTABLE * () const { return Ptr(); }
1344
1345 private:
1346 PBYTEArray buffer;
1347 };
1348
1349
1350 class PIPInterfaceAddressTable
1351 {
1352 public:
PIPInterfaceAddressTable()1353 PIPInterfaceAddressTable()
1354 {
1355 ULONG size = 0;
1356 DWORD error = GetIpAddrTable(NULL, &size, FALSE);
1357 if (error == ERROR_INSUFFICIENT_BUFFER && buffer.SetSize(size))
1358 error = GetIpAddrTable((MIB_IPADDRTABLE *)buffer.GetPointer(), &size, FALSE);
1359 if (error != NO_ERROR) {
1360 buffer.SetSize(0);
1361 buffer.SetSize(sizeof(MIB_IPADDRTABLE)); // So ->NumAdapters returns zero
1362 }
1363 }
1364
Ptr() const1365 const MIB_IPADDRTABLE * Ptr() const { return (const MIB_IPADDRTABLE *)(const BYTE *)buffer; }
operator ->() const1366 const MIB_IPADDRTABLE * operator->() const { return Ptr(); }
operator *() const1367 const MIB_IPADDRTABLE & operator *() const { return *Ptr(); }
operator const MIB_IPADDRTABLE*() const1368 operator const MIB_IPADDRTABLE * () const { return Ptr(); }
1369
1370 private:
1371 PBYTEArray buffer;
1372 };
1373
1374
1375 #if IPv6_ENABLED
1376 class PIPAdaptersAddressTable
1377 {
1378 public:
1379
PIPAdaptersAddressTable(DWORD dwFlags=GAA_FLAG_INCLUDE_PREFIX|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_MULTICAST)1380 PIPAdaptersAddressTable(DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX
1381 | GAA_FLAG_SKIP_ANYCAST
1382 | GAA_FLAG_SKIP_DNS_SERVER
1383 | GAA_FLAG_SKIP_MULTICAST)
1384 {
1385 ULONG size = 0;
1386 DWORD error = GetAdaptersAddresses(AF_UNSPEC, dwFlags, NULL, NULL, &size);
1387 if (buffer.SetSize(size))
1388 error = GetAdaptersAddresses(AF_UNSPEC, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)buffer.GetPointer(), &size);
1389
1390 if (error != NO_ERROR) {
1391 buffer.SetSize(0);
1392 buffer.SetSize(sizeof(IP_ADAPTER_ADDRESSES)); // So ->NumAdapters returns zero
1393 }
1394 }
1395
Ptr() const1396 const IP_ADAPTER_ADDRESSES * Ptr() const { return (const IP_ADAPTER_ADDRESSES *)(const BYTE *)buffer; }
operator ->() const1397 const IP_ADAPTER_ADDRESSES * operator->() const { return Ptr(); }
operator *() const1398 const IP_ADAPTER_ADDRESSES & operator *() const { return *Ptr(); }
operator const IP_ADAPTER_ADDRESSES*() const1399 operator const IP_ADAPTER_ADDRESSES * () const { return Ptr(); }
1400
1401 private:
1402 PBYTEArray buffer;
1403 };
1404
1405
1406 #include <tchar.h>
1407
1408 class PIPRouteTableIPv6 : public PIPRouteTable
1409 {
1410 public:
1411
PIPRouteTableIPv6()1412 PIPRouteTableIPv6()
1413 {
1414 buffer.SetSize(sizeof(MIB_IPFORWARD_TABLE2)); // So ->NumEntries returns zero
1415
1416 HINSTANCE hInst = LoadLibrary(_T("iphlpapi.dll"));
1417 if (hInst != NULL) {
1418 GETIPFORWARDTABLE2 pfGetIpForwardTable2 = (GETIPFORWARDTABLE2)GetProcAddress(hInst, _T("GetIpForwardTable2"));
1419 FREEMIBTABLE pfFreeMibTable = (FREEMIBTABLE)GetProcAddress(hInst, _T("FreeMibTable"));
1420 if (pfGetIpForwardTable2 != NULL && pfFreeMibTable != NULL) {
1421 PMIB_IPFORWARD_TABLE2 pt = NULL;
1422 DWORD dwError = (*pfGetIpForwardTable2)(AF_UNSPEC, &pt);
1423 if (dwError == NO_ERROR) {
1424 buffer.SetSize(pt->NumEntries * sizeof(MIB_IPFORWARD_ROW2));
1425 memcpy(buffer.GetPointer(), pt, buffer.GetSize());
1426 (*pfFreeMibTable)(pt);
1427 }
1428 }
1429 FreeLibrary(hInst);
1430 }
1431 }
1432
Ptr() const1433 const MIB_IPFORWARD_TABLE2 * Ptr() const { return (const MIB_IPFORWARD_TABLE2 *)(const BYTE *)buffer; }
operator ->() const1434 const MIB_IPFORWARD_TABLE2 * operator->() const { return Ptr(); }
operator *() const1435 const MIB_IPFORWARD_TABLE2 & operator *() const { return *Ptr(); }
operator const MIB_IPFORWARD_TABLE2*() const1436 operator const MIB_IPFORWARD_TABLE2 * () const { return Ptr(); }
1437
1438
ValidateAddress(DWORD ifIndex,LPSOCKADDR lpSockAddr)1439 bool ValidateAddress(DWORD ifIndex, LPSOCKADDR lpSockAddr)
1440 {
1441 int numEntries = Ptr()->NumEntries;
1442 if (numEntries == 0)
1443 return true;
1444
1445 if (lpSockAddr == NULL)
1446 return false;
1447
1448 const MIB_IPFORWARD_ROW2 * row = Ptr()->Table;
1449 for (int i = 0; i < numEntries; i++, row++) {
1450 if (row->InterfaceIndex == ifIndex &&
1451 row->DestinationPrefix.Prefix.si_family == lpSockAddr->sa_family) {
1452 switch (lpSockAddr->sa_family) {
1453 case AF_INET :
1454 if (row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == ((sockaddr_in *)lpSockAddr)->sin_addr.S_un.S_addr)
1455 return true;
1456 break;
1457
1458 case AF_INET6 :
1459 if (memcmp(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,
1460 ((sockaddr_in6 *)lpSockAddr)->sin6_addr.u.Byte, sizeof(in6_addr)) == 0)
1461 return true;
1462 }
1463 }
1464 }
1465
1466 return false;
1467 }
1468
1469 private:
1470 PBYTEArray buffer;
1471 };
1472 #endif // IPv6_ENABLED
1473
1474
1475 ///////////////////////////////////////////////////////////////////////////////
1476
GetGatewayAddress(Address & addr,int version)1477 PBoolean PIPSocket::GetGatewayAddress(Address & addr, int version)
1478 {
1479 if (version == 6) {
1480 #if IPv6_ENABLED
1481 PIPRouteTableIPv6 routes;
1482 int numEntries = routes->NumEntries;
1483 if (numEntries > 0) {
1484 const MIB_IPFORWARD_ROW2 * row = routes->Table;
1485 for (int i = 0; i < numEntries; i++, row++) {
1486 if (row->NextHop.si_family == AF_INET6) {
1487 PIPSocket::Address hop(row->NextHop.Ipv6.sin6_addr);
1488 if (hop.IsValid()) {
1489 addr = hop;
1490 return true;
1491 }
1492 }
1493 }
1494 }
1495 #endif
1496 return false;
1497 }
1498
1499 PIPRouteTable routes;
1500 for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1501 if (routes->table[i].dwForwardMask == 0) {
1502 addr = routes->table[i].dwForwardNextHop;
1503 return true;
1504 }
1505 }
1506 return false;
1507 }
1508
1509
GetGatewayInterface(int version)1510 PString PIPSocket::GetGatewayInterface(int version)
1511 {
1512 if (version == 6) {
1513 #if IPv6_ENABLED
1514 PIPRouteTableIPv6 routes;
1515 int numEntries = routes->NumEntries;
1516 if (numEntries > 0) {
1517 const MIB_IPFORWARD_ROW2 * row = routes->Table;
1518 for (int i = 0; i < numEntries; i++, row++) {
1519 if (row->NextHop.si_family == AF_INET6 && PIPSocket::Address(row->NextHop.Ipv6.sin6_addr).IsValid()) {
1520 PIPAdaptersAddressTable adapters;
1521 for (const IP_ADAPTER_ADDRESSES * adapter = &*adapters; adapter != NULL; adapter = adapter->Next) {
1522 if (adapter->IfIndex == row->InterfaceIndex)
1523 return adapter->Description;
1524 }
1525 }
1526 }
1527 }
1528 #endif
1529 return PString::Empty();
1530 }
1531
1532 PIPRouteTable routes;
1533 for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1534 if (routes->table[i].dwForwardMask == 0) {
1535 MIB_IFROW info;
1536 info.dwIndex = routes->table[i].dwForwardIfIndex;
1537 if (GetIfEntry(&info) == NO_ERROR)
1538 return PString((const char *)info.bDescr, info.dwDescrLen);
1539 }
1540 }
1541 return PString::Empty();
1542 }
1543
1544
GetGatewayInterfaceAddress(int version)1545 PIPSocket::Address PIPSocket::GetGatewayInterfaceAddress(int version)
1546 {
1547 if (version == 6) {
1548 #if IPv6_ENABLED
1549 PIPRouteTableIPv6 routes;
1550 if (routes->NumEntries > 0) {
1551 PIPAdaptersAddressTable interfaces;
1552
1553 for (const IP_ADAPTER_ADDRESSES * adapter = &*interfaces; adapter != NULL; adapter = adapter->Next) {
1554 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = adapter->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) {
1555 if (unicast->Address.lpSockaddr->sa_family != AF_INET6)
1556 continue;
1557
1558 PIPSocket::Address ip(((sockaddr_in6 *)unicast->Address.lpSockaddr)->sin6_addr);
1559
1560 if (routes->NumEntries == 0)
1561 return ip;
1562
1563 // Check if local-link addresses supported (scope_id != 0)
1564 if ((PIPSocket::GetDefaultV6ScopeId() || (ip[0] != 0xFE && ip[1] != 0x80))
1565 &&
1566 routes.ValidateAddress(adapter->IfIndex, unicast->Address.lpSockaddr))
1567 return ip;
1568 }
1569 }
1570 }
1571 #else
1572 return GetDefaultIpAny();
1573 #endif
1574 }
1575
1576 PIPRouteTable routes;
1577 for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1578 if (routes->table[i].dwForwardMask == 0) {
1579 PIPInterfaceAddressTable interfaces;
1580 for (unsigned j = 0; j < interfaces->dwNumEntries; ++j) {
1581 if (interfaces->table[j].dwIndex == routes->table[i].dwForwardIfIndex)
1582 return interfaces->table[j].dwAddr;
1583 }
1584 }
1585 }
1586
1587 return GetDefaultIpAny();
1588 }
1589
1590
GetRouteTable(RouteTable & table)1591 PBoolean PIPSocket::GetRouteTable(RouteTable & table)
1592 {
1593 PIPRouteTable routes;
1594
1595 if (!table.SetSize(routes->dwNumEntries))
1596 return false;
1597
1598 if (table.IsEmpty())
1599 return false;
1600
1601 for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1602 RouteEntry * entry = new RouteEntry(routes->table[i].dwForwardDest);
1603 entry->net_mask = routes->table[i].dwForwardMask;
1604 entry->destination = routes->table[i].dwForwardNextHop;
1605 entry->metric = routes->table[i].dwForwardMetric1;
1606
1607 MIB_IFROW info;
1608 info.dwIndex = routes->table[i].dwForwardIfIndex;
1609 if (GetIfEntry(&info) == NO_ERROR)
1610 entry->interfaceName = PString((const char *)info.bDescr, info.dwDescrLen);
1611 table.SetAt(i, entry);
1612 }
1613
1614 return true;
1615 }
1616
1617
1618 #ifdef _MSC_VER
1619 #pragma optimize("g", off)
1620 #endif
1621
1622 class Win32RouteTableDetector : public PIPSocket::RouteTableDetector
1623 {
1624 PDynaLink m_dll;
1625 BOOL (WINAPI * m_pCancelIPChangeNotify )(LPOVERLAPPED);
1626 HANDLE m_hCancel;
1627
1628 public:
Win32RouteTableDetector()1629 Win32RouteTableDetector()
1630 : m_dll("iphlpapi.dll")
1631 , m_hCancel(CreateEvent(NULL, TRUE, FALSE, NULL))
1632 {
1633 if (!m_dll.GetFunction("CancelIPChangeNotify", (PDynaLink::Function&)m_pCancelIPChangeNotify))
1634 m_pCancelIPChangeNotify = NULL;
1635 }
1636
~Win32RouteTableDetector()1637 ~Win32RouteTableDetector()
1638 {
1639 if (m_hCancel != NULL)
1640 CloseHandle(m_hCancel);
1641 }
1642
Wait(const PTimeInterval & timeout)1643 virtual bool Wait(const PTimeInterval & timeout)
1644 {
1645 HANDLE hNotify = NULL;
1646 OVERLAPPED overlap;
1647
1648 if (m_pCancelIPChangeNotify != NULL) {
1649 memset(&overlap, 0, sizeof(overlap));
1650 DWORD error = NotifyAddrChange(&hNotify, &overlap);
1651 if (error != ERROR_IO_PENDING) {
1652 PTRACE(1, "PTlib\tCould not get network interface change notification: error=" << error);
1653 hNotify = NULL;
1654 }
1655 }
1656
1657 if (hNotify == NULL)
1658 return WaitForSingleObject(m_hCancel, timeout.GetInterval()) == WAIT_TIMEOUT;
1659
1660 HANDLE handles[2];
1661 handles[0] = hNotify;
1662 handles[1] = m_hCancel;
1663 switch (WaitForMultipleObjects(2, handles, false, INFINITE)) {
1664 case WAIT_OBJECT_0 :
1665 return true;
1666
1667 case WAIT_OBJECT_0+1 :
1668 if (m_pCancelIPChangeNotify != NULL)
1669 m_pCancelIPChangeNotify(&overlap);
1670 // Do next case
1671
1672 default :
1673 return false;
1674 }
1675 }
1676
Cancel()1677 virtual void Cancel()
1678 {
1679 SetEvent(m_hCancel);
1680 }
1681 };
1682
1683 #ifdef _MSC_VER
1684 #pragma optimize("", on)
1685 #endif
1686
1687
CreateRouteTableDetector()1688 PIPSocket::RouteTableDetector * PIPSocket::CreateRouteTableDetector()
1689 {
1690 return new Win32RouteTableDetector();
1691 }
1692
1693
GetRouteAddress(PIPSocket::Address remoteAddress)1694 PIPSocket::Address PIPSocket::GetRouteAddress(PIPSocket::Address remoteAddress)
1695 {
1696 DWORD best;
1697 if (GetBestInterface(remoteAddress, &best) == NO_ERROR) {
1698 PIPInterfaceAddressTable interfaces;
1699 for (unsigned j = 0; j < interfaces->dwNumEntries; ++j) {
1700 if (interfaces->table[j].dwIndex == best)
1701 return interfaces->table[j].dwAddr;
1702 }
1703 }
1704 return GetDefaultIpAny();
1705 }
1706
1707
AsNumeric(PIPSocket::Address addr)1708 unsigned PIPSocket::AsNumeric(PIPSocket::Address addr)
1709 {
1710 return ((addr.Byte1() << 24) | (addr.Byte2() << 16) | (addr.Byte3() << 8) | addr.Byte4());
1711 }
1712
IsAddressReachable(PIPSocket::Address localIP,PIPSocket::Address localMask,PIPSocket::Address remoteIP)1713 PBoolean PIPSocket::IsAddressReachable(PIPSocket::Address localIP,
1714 PIPSocket::Address localMask,
1715 PIPSocket::Address remoteIP)
1716 {
1717 BYTE t = 255;
1718 int t1=t,t2=t,t3 =t,t4=t;
1719 int b1=0,b2=0,b3=0,b4=0;
1720
1721 if ((int)localMask.Byte1() > 0) {
1722 t1 = localIP.Byte1() + (t - localMask.Byte1());
1723 b1 = localIP.Byte1();
1724 }
1725
1726 if ((int)localMask.Byte2() > 0) {
1727 t2 = localIP.Byte2() + (t - localMask.Byte2());
1728 b2 = localIP.Byte2();
1729 }
1730
1731 if ((int)localMask.Byte3() > 0) {
1732 t3 = localIP.Byte3() + (t - localMask.Byte3());
1733 b3 = localIP.Byte3();
1734 }
1735
1736 if ((int)localMask.Byte4() > 0) {
1737 t4 = localIP.Byte4() + (t - localMask.Byte4());
1738 b4 = localIP.Byte4();
1739 }
1740
1741 Address lt = Address((BYTE)t1,(BYTE)t2,(BYTE)t3,(BYTE)t4);
1742 Address lb = Address((BYTE)b1,(BYTE)b2,(BYTE)b3,(BYTE)b4);
1743
1744 return AsNumeric(remoteIP) > AsNumeric(lb) && AsNumeric(lt) > AsNumeric(remoteIP);
1745 }
1746
1747
GetInterface(PIPSocket::Address addr)1748 PString PIPSocket::GetInterface(PIPSocket::Address addr)
1749 {
1750 PIPInterfaceAddressTable byAddress;
1751 for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1752 if (addr == byAddress->table[i].dwAddr) {
1753 MIB_IFROW info;
1754 info.dwIndex = byAddress->table[i].dwIndex;
1755 if (GetIfEntry(&info) == NO_ERROR)
1756 return PString((const char *)info.bDescr, info.dwDescrLen);
1757 }
1758 }
1759
1760 return PString::Empty();
1761 }
1762
1763
GetInterfaceTable(InterfaceTable & table,PBoolean includeDown)1764 PBoolean PIPSocket::GetInterfaceTable(InterfaceTable & table, PBoolean includeDown)
1765 {
1766 #if IPv6_ENABLED
1767 // Adding IPv6 addresses
1768 PIPRouteTableIPv6 routes;
1769 PIPAdaptersAddressTable interfaces;
1770 PIPInterfaceAddressTable byAddress;
1771
1772 PINDEX count = 0; // address count
1773
1774 if (!table.SetSize(0))
1775 return false;
1776
1777 for (const IP_ADAPTER_ADDRESSES * adapter = &*interfaces; adapter != NULL; adapter = adapter->Next) {
1778 if (!includeDown && (adapter->OperStatus != IfOperStatusUp))
1779 continue;
1780
1781 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = adapter->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) {
1782 if (!routes.ValidateAddress(adapter->IfIndex, unicast->Address.lpSockaddr))
1783 continue;
1784
1785 PStringStream macAddr;
1786 macAddr << ::hex << ::setfill('0');
1787 for (unsigned b = 0; b < adapter->PhysicalAddressLength; ++b)
1788 macAddr << setw(2) << (unsigned)adapter->PhysicalAddress[b];
1789
1790 if (unicast->Address.lpSockaddr->sa_family == AF_INET && PIPSocket::GetDefaultIpAddressFamily() == AF_INET) {
1791 PIPSocket::Address ip(((sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr);
1792
1793 // Find out address index in byAddress table for the mask
1794 DWORD dwMask = 0L;
1795 for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1796 if (adapter->IfIndex == byAddress->table[i].dwIndex) {
1797 dwMask = byAddress->table[i].dwMask;
1798 break;
1799 }
1800 } // find mask for the address
1801
1802 table.SetAt(count++, new InterfaceEntry(adapter->Description, ip, dwMask, macAddr));
1803
1804 } // ipv4
1805 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6 && PIPSocket::GetDefaultIpAddressFamily() == AF_INET6) {
1806 PIPSocket::Address ip(((sockaddr_in6 *)unicast->Address.lpSockaddr)->sin6_addr);
1807
1808 // Check if local-link addresses supported (scope_id != 0)
1809 if (PIPSocket::GetDefaultV6ScopeId() || (ip[0] != 0xFE && ip[1] != 0x80))
1810 table.SetAt(count++, new InterfaceEntry(adapter->Description, ip, 0L, macAddr));
1811 } // ipv6
1812 }
1813 }
1814
1815 #else
1816
1817 PIPInterfaceAddressTable byAddress;
1818
1819 if (!table.SetSize(byAddress->dwNumEntries))
1820 return false;
1821
1822 if (table.IsEmpty())
1823 return false;
1824
1825 PINDEX count = 0;
1826 for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1827 Address addr = byAddress->table[i].dwAddr;
1828
1829 MIB_IFROW info;
1830 info.dwIndex = byAddress->table[i].dwIndex;
1831 if (GetIfEntry(&info) == NO_ERROR && (includeDown || (addr.IsValid() && info.dwAdminStatus))) {
1832 PStringStream macAddr;
1833 macAddr << ::hex << ::setfill('0');
1834 for (unsigned b = 0; b < info.dwPhysAddrLen; ++b)
1835 macAddr << setw(2) << (unsigned)info.bPhysAddr[b];
1836
1837 table.SetAt(count++, new InterfaceEntry(PString((const char *)info.bDescr, info.dwDescrLen),
1838 addr,
1839 byAddress->table[i].dwMask,
1840 macAddr));
1841 }
1842 }
1843
1844 table.SetSize(count); // May shrink due to "down" interfaces.
1845
1846 #endif
1847
1848 return true;
1849 }
1850
1851
1852 ///////////////////////////////////////////////////////////////////////////////
1853