4 * Direct Ethernet socket implementation.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
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/
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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.43 2004/06/30 12:17:06 rjongbloed
31 * Rewrite of plug in system to use single global variable for all factories to avoid all sorts
32 * of issues with startup orders and Windows DLL multiple instances.
34 * Revision 1.42 2004/06/08 01:19:22 csoutheren
35 * Fixed problem with SNMP library not loading under Windows in some cases
37 * Revision 1.41 2004/06/01 05:24:12 csoutheren
38 * Changed loading of inetmib1.dll to use PProcessStartup to avoid crashes when it is unloaded before ~H323Endpoint is called
40 * Revision 1.40 2004/01/30 02:06:06 csoutheren
41 * Added mutex to avoid threading problems on Windows
42 * Thanks to Hans Verbeek
44 * Revision 1.39 2003/11/05 22:51:22 csoutheren
45 * Added pragma to automatically included required libs
47 * Revision 1.38 2003/09/17 05:45:10 csoutheren
48 * Removed recursive includes
50 * Revision 1.37 2003/04/01 06:01:48 robertj
51 * Fixed problem with returning correct route table device name if have
52 * 2 NIC's under Windows 2000, thanks faa06@tid.es
54 * Revision 1.36 2003/01/11 05:10:51 robertj
55 * Fixed Win CE compatibility issues, thanks Joerg Schoemer
57 * Revision 1.35 2002/11/12 02:22:16 robertj
58 * Fixed problem where if SNMP not correctly installed on some flavours of
59 * windows (eg ME) the system cannot find any interfaces. Added fail safe
60 * that if could not determine one, it uses the ip address of gethostname()
61 * which should be one of the interfaces on the system.
63 * Revision 1.34 2002/11/08 06:45:23 robertj
64 * Fixed problem with very long interface names, pointed out by Kees Klop.
66 * Revision 1.33 2002/10/08 12:41:52 robertj
67 * Changed for IPv6 support, thanks Sébastien Josset.
69 * Revision 1.32 2002/02/25 09:57:29 robertj
70 * Fixed possible NULL pointer use and memory leak, thanks Klaus König
72 * Revision 1.31 2002/02/15 03:56:46 yurik
73 * Warnings removed during compilation, patch courtesy of Jehan Bing, jehan@bravobrava.com
75 * Revision 1.30 2001/10/12 19:04:24 yurik
76 * New more robust ip collection routine
78 * Revision 1.29 2001/10/04 05:59:41 robertj
79 * Plugged numerous memory leaks.
81 * Revision 1.28 2001/10/03 03:12:21 robertj
82 * Changed to use only a single instance of SNMP library to avoid memory leak.
84 * Revision 1.27 2001/09/10 02:51:23 robertj
85 * Major change to fix problem with error codes being corrupted in a
86 * PChannel when have simultaneous reads and writes in threads.
88 * Revision 1.26 2001/09/09 02:03:49 yurik
91 * Revision 1.25 2001/08/28 03:22:01 yurik
92 * Fixed crash on snmp init bug
94 * Revision 1.24 2001/08/16 20:12:25 yurik
95 * Fixed duplicate ordinal - ifdef'd ce code
97 * Revision 1.23 2001/08/15 22:15:27 yurik
98 * First cut of Windows CE port to support gatekeeper
100 * Revision 1.22 2001/03/05 04:18:27 robertj
101 * Added net mask to interface info returned by GetInterfaceTable()
103 * Revision 1.21 2000/03/06 03:59:22 robertj
104 * Fixed warning about handle types, thanks Steve Bennett
106 * Revision 1.20 1999/10/29 03:34:19 robertj
107 * Fixed possible crash accessing IP addresses from SNMP tables.
109 * Revision 1.19 1999/10/14 01:34:55 robertj
110 * Fixed backward compatibility problem with old SNMP header file.
112 * Revision 1.18 1999/09/10 04:35:42 robertj
113 * Added Windows version of PIPSocket::GetInterfaceTable() function.
115 * Revision 1.17 1999/04/18 12:58:39 robertj
116 * MSVC 5 backward compatibility
118 * Revision 1.16 1999/02/16 08:08:06 robertj
119 * MSVC 6.0 compatibility changes.
121 * Revision 1.15 1998/11/30 04:48:38 robertj
122 * New directory structure
124 * Revision 1.14 1998/11/22 11:30:10 robertj
125 * Check route table function to get a list
127 * Revision 1.13 1998/11/20 03:17:43 robertj
128 * Split rad and write buffers to separate pools.
130 * Revision 1.12 1998/11/19 05:18:48 robertj
131 * Added route table manipulation functions to PIPSocket class.
133 * Revision 1.11 1998/11/14 06:31:41 robertj
134 * Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
135 * Added support for MSDUN1.3 DHCP registry entries.
137 * Revision 1.10 1998/10/23 04:09:08 robertj
138 * Fixes for NT support.
139 * Allowed both old and new driver by compilation option.
141 * Revision 1.9 1998/10/15 05:41:48 robertj
142 * New memory leak check code.
144 * Revision 1.8 1998/10/12 09:34:42 robertj
145 * New method for getting IP addresses of interfaces.
147 * Revision 1.7 1998/10/06 10:24:41 robertj
148 * Fixed hang when using reset command, removed the command!
150 * Revision 1.6 1998/09/24 03:30:45 robertj
151 * Added open software license.
153 * Revision 1.5 1998/09/15 08:25:36 robertj
154 * Fixed a number of warnings at maximum optimisation.
156 * Revision 1.4 1998/09/08 15:14:36 robertj
157 * Fixed packet type based filtering in Read() function.
159 * Revision 1.3 1998/08/25 11:03:15 robertj
160 * Fixed proble with NT get of OID.
161 * Fixed bug with not setting channel name when interface opened.
163 * Revision 1.2 1998/08/21 05:27:13 robertj
164 * Fine tuning of interface.
166 * Revision 1.1 1998/08/20 06:04:52 robertj
172 #include <ptlib/sockets.h>
175 #pragma comment(lib, "snmpapi.lib")
177 ///////////////////////////////////////////////////////////////////////////////
180 #ifndef RFC1157VarBindList
181 typedef RFC1157VarBind SnmpVarBind
;
182 typedef RFC1157VarBindList SnmpVarBindList
;
183 typedef LONG AsnInteger32
;
184 #define SNMP_PDU_GET ASN_RFC1157_GETREQUEST
185 #define SNMP_PDU_GETNEXT ASN_RFC1157_GETNEXTREQUEST
186 #define ASN_IPADDRESS ASN_RFC1155_IPADDRESS // Prevents GetInterfaceTable failure
187 #pragma message("Later version of snmp.h required!")
190 ///////////////////////////////////////////////////////////////////////////////
193 #define OID_802_3_PERMANENT_ADDRESS 0x01010101
194 #define OID_802_3_CURRENT_ADDRESS 0x01010102
196 #define OID_GEN_DRIVER_VERSION 0x00010110
197 #define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
198 #define OID_GEN_MEDIA_SUPPORTED 0x00010103
200 #define NDIS_PACKET_TYPE_DIRECTED 0x0001
201 #define NDIS_PACKET_TYPE_MULTICAST 0x0002
202 #define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
203 #define NDIS_PACKET_TYPE_BROADCAST 0x0008
204 #define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
206 typedef enum _NDIS_MEDIUM
{
212 NdisMediumDix
, // defined for convenience, not a real medium
214 NdisMediumArcnet878_2
215 } NDIS_MEDIUM
, *PNDIS_MEDIUM
;
217 ///////////////////////////////////////////////////////////////////////////////
221 #include <ptlib/msos/ptlib/epacket.h>
224 #define PACKET_SERVICE_NAME "Packet"
225 #define PACKET_VXD_NAME "VPacket"
227 #define PACKET_SERVICE_NAME "EPacket"
228 #define PACKET_VXD_NAME "EPacket"
229 #define GetQueryOidCommand(oid) IOCTL_EPACKET_QUERY_OID
232 #define SERVICES_REGISTRY_KEY "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\"
235 ///////////////////////////////////////////////////////////////////////////////
237 class PWin32AsnAny
: public AsnAny
241 ~PWin32AsnAny() { MemFree(); }
242 BOOL
GetInteger(AsnInteger
& i
);
243 BOOL
GetIpAddress(PIPSocket::Address
& addr
);
246 PWin32AsnAny(const PWin32AsnAny
&) { }
247 PWin32AsnAny
& operator=(const PWin32AsnAny
&) { return *this; }
251 ///////////////////////////////////////////////////////////////////////////////
253 class PWin32AsnOid
: public AsnObjectIdentifier
257 PWin32AsnOid(const char * str
);
258 PWin32AsnOid(const PWin32AsnOid
& oid
) { SnmpUtilOidCpy(this, (AsnObjectIdentifier
*)&oid
); }
259 ~PWin32AsnOid() { SnmpUtilOidFree(this); }
260 PWin32AsnOid
& operator=(const AsnObjectIdentifier
&);
261 PWin32AsnOid
& operator=(const PWin32AsnOid
& oid
) { SnmpUtilOidFree(this); SnmpUtilOidCpy(this, (AsnObjectIdentifier
*)&oid
); return *this; }
262 PWin32AsnOid
& operator+=(const PWin32AsnOid
& oid
) { SnmpUtilOidAppend(this, (AsnObjectIdentifier
*)&oid
); return *this; }
263 UINT
& operator[](int idx
) { return ids
[idx
]; }
264 UINT
operator[](int idx
) const { return ids
[idx
]; }
265 bool operator==(const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) == 0; }
266 bool operator!=(const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) != 0; }
267 bool operator< (const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) < 0; }
268 bool operator<=(const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) <= 0; }
269 bool operator> (const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) > 0; }
270 bool operator>=(const PWin32AsnOid
& oid
) { return SnmpUtilOidCmp(this, (AsnObjectIdentifier
*)&oid
) >= 0; }
271 bool operator*=(const PWin32AsnOid
& oid
) { return SnmpUtilOidNCmp(this, (AsnObjectIdentifier
*)&oid
, idLength
) == 0; }
275 /////////////////////////////////////////////////////////////////////////////
277 class PWin32SnmpLibrary
281 PCLASSINFO(PWin32SnmpLibrary
, PDynaLink
)
287 BOOL
IsLoaded() { return TRUE
; }
292 BOOL
GetOid(AsnObjectIdentifier
& oid
, AsnInteger
& value
);
293 BOOL
GetOid(AsnObjectIdentifier
& oid
, PIPSocket::Address
& ip_address
);
294 BOOL
GetOid(AsnObjectIdentifier
& oid
, PString
& str
);
295 BOOL
GetOid(AsnObjectIdentifier
& oid
, void * value
, UINT valSize
, UINT
* len
= NULL
);
296 BOOL
GetOid(AsnObjectIdentifier
& oid
, PWin32AsnAny
& value
) { return QueryOid(SNMP_PDU_GET
, oid
, value
); }
298 BOOL
GetNextOid(AsnObjectIdentifier
& oid
, PWin32AsnAny
& value
) { return QueryOid(SNMP_PDU_GETNEXT
, oid
, value
); }
300 PString
GetInterfaceName(int ifNum
);
301 PString
GetInterfaceName(PIPSocket::Address ipAddr
);
303 static PWin32SnmpLibrary
& Current();
304 static PMutex
& GetMutex();
309 BOOL (WINAPI
*_Init
)(DWORD
,HANDLE
*,AsnObjectIdentifier
*);
310 BOOL (WINAPI
*_Query
)(BYTE
,SnmpVarBindList
*,AsnInteger32
*,AsnInteger32
*);
312 BOOL
Init(DWORD upTime
, HANDLE
* trapEvent
, AsnObjectIdentifier
* firstSupportedRegion
)
313 { return (*_Init
)(upTime
, trapEvent
, firstSupportedRegion
); }
315 BOOL
Query(BYTE pduType
, SnmpVarBindList
* pVarBindList
, AsnInteger32
* pErrorStatus
, AsnInteger32
* pErrorIndex
)
316 { return _Query(pduType
, pVarBindList
, pErrorStatus
, pErrorIndex
); }
318 BOOL
QueryOid(BYTE cmd
, AsnObjectIdentifier
& oid
, PWin32AsnAny
& value
);
321 class WinSNMPLoader
: public PProcessStartup
323 PCLASSINFO(WinSNMPLoader
, PProcessStartup
);
328 PWin32SnmpLibrary
& Current()
330 PWaitAndSignal
m(mutex
);
331 if (snmpLibrary
== NULL
) {
332 snmpLibrary
= new PWin32SnmpLibrary
;
339 PWaitAndSignal
m(mutex
);
346 static PWin32SnmpLibrary
* snmpLibrary
;
349 PWin32SnmpLibrary
* WinSNMPLoader::snmpLibrary
= NULL
;
351 static PFactory
<PProcessStartup
>::Worker
<WinSNMPLoader
> winSNMPLoadedStartupFactory("WinSNMPLoader", true);
353 PWin32SnmpLibrary
& PWin32SnmpLibrary::Current()
355 return ((WinSNMPLoader
*)PFactory
<PProcessStartup
>::CreateInstance("WinSNMPLoader"))->Current();
358 PMutex
& PWin32SnmpLibrary::GetMutex()
360 return Current().mutex
;
363 #define GetSNMPMutex PWin32SnmpLibrary::GetMutex
365 ///////////////////////////////////////////////////////////////////////////////
367 class PWin32OidBuffer
370 PWin32OidBuffer(UINT oid
, UINT len
, const BYTE
* data
= NULL
);
371 ~PWin32OidBuffer() { delete buffer
; }
373 operator void *() { return buffer
; }
374 operator DWORD () { return size
; }
375 DWORD
operator [](int i
) { return buffer
[i
]; }
377 void Move(BYTE
* data
, DWORD received
);
385 ///////////////////////////////////////////////////////////////////////////////
387 class PWin32PacketDriver
390 static PWin32PacketDriver
* Create();
392 virtual ~PWin32PacketDriver();
396 DWORD
GetLastError() const;
398 virtual BOOL
EnumInterfaces(PINDEX idx
, PString
& name
) = 0;
399 virtual BOOL
BindInterface(const PString
& interfaceName
) = 0;
401 virtual BOOL
EnumIpAddress(PINDEX idx
, PIPSocket::Address
& addr
, PIPSocket::Address
& net_mask
) = 0;
403 virtual BOOL
BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
) = 0;
404 virtual BOOL
BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
) = 0;
405 BOOL
CompleteIO(DWORD
& received
, PWin32Overlapped
& overlap
);
407 BOOL
IoControl(UINT func
,
408 const void * input
, DWORD inSize
,
409 void * output
, DWORD outSize
,
412 BOOL
QueryOid(UINT oid
, DWORD
& data
);
413 BOOL
QueryOid(UINT oid
, UINT len
, BYTE
* data
);
414 BOOL
SetOid(UINT oid
, DWORD data
);
415 BOOL
SetOid(UINT oid
, UINT len
, const BYTE
* data
);
417 virtual UINT
GetQueryOidCommand(DWORD oid
) const = 0;
421 PWin32PacketDriver();
427 ///////////////////////////////////////////////////////////////////////////////
429 class PWin32PacketVxD
: public PWin32PacketDriver
432 virtual BOOL
EnumInterfaces(PINDEX idx
, PString
& name
);
433 virtual BOOL
BindInterface(const PString
& interfaceName
);
435 virtual BOOL
EnumIpAddress(PINDEX idx
, PIPSocket::Address
& addr
, PIPSocket::Address
& net_mask
);
437 virtual BOOL
BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
);
438 virtual BOOL
BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
);
441 virtual UINT
GetQueryOidCommand(DWORD oid
) const
442 { return oid
>= OID_802_3_PERMANENT_ADDRESS
? IOCTL_EPACKET_QUERY_OID
: IOCTL_EPACKET_STATISTICS
; }
446 PStringList transportBinding
;
450 ///////////////////////////////////////////////////////////////////////////////
452 class PWin32PacketSYS
: public PWin32PacketDriver
457 virtual BOOL
EnumInterfaces(PINDEX idx
, PString
& name
);
458 virtual BOOL
BindInterface(const PString
& interfaceName
);
460 virtual BOOL
EnumIpAddress(PINDEX idx
, PIPSocket::Address
& addr
, PIPSocket::Address
& net_mask
);
462 virtual BOOL
BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
);
463 virtual BOOL
BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
);
466 virtual UINT
GetQueryOidCommand(DWORD
) const
467 { return IOCTL_EPACKET_QUERY_OID
; }
474 ///////////////////////////////////////////////////////////////////////////////
478 class PWin32PacketCe
: public PWin32PacketDriver
483 virtual BOOL
EnumInterfaces(PINDEX idx
, PString
& name
);
484 virtual BOOL
BindInterface(const PString
& interfaceName
);
486 virtual BOOL
EnumIpAddress(PINDEX idx
, PIPSocket::Address
& addr
, PIPSocket::Address
& net_mask
);
488 virtual BOOL
BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
);
489 virtual BOOL
BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
);
492 virtual UINT
GetQueryOidCommand(DWORD
) const
493 { return IOCTL_EPACKET_QUERY_OID
; }
496 PStringArray ipAddresses
;
497 PStringArray netMasks
;
498 PStringArray interfaces
;
503 /////////////////////////////////////////////////////////////////////////////
505 class PWin32PacketBuffer
: public PBYTEArray
507 PCLASSINFO(PWin32PacketBuffer
, PBYTEArray
)
515 PWin32PacketBuffer(PINDEX sz
);
517 PINDEX
GetData(void * buf
, PINDEX size
);
518 PINDEX
PutData(const void * buf
, PINDEX length
);
519 HANDLE
GetEvent() const { return overlap
.hEvent
; }
521 BOOL
ReadAsync(PWin32PacketDriver
& pkt
);
522 BOOL
ReadComplete(PWin32PacketDriver
& pkt
);
523 BOOL
WriteAsync(PWin32PacketDriver
& pkt
);
524 BOOL
WriteComplete(PWin32PacketDriver
& pkt
);
526 BOOL
InProgress() const { return status
== Progressing
; }
527 BOOL
IsCompleted() const { return status
== Completed
; }
528 BOOL
IsType(WORD type
) const;
532 PWin32Overlapped overlap
;
540 /////////////////////////////////////////////////////////////////////////////
542 PWin32AsnAny::PWin32AsnAny()
544 asnType
= ASN_INTEGER
;
549 void PWin32AsnAny::MemFree()
552 case ASN_OCTETSTRING
:
553 SnmpUtilMemFree(asnValue
.string
.stream
);
557 SnmpUtilMemFree(asnValue
.bits
.stream
);
560 case ASN_OBJECTIDENTIFIER
:
561 SnmpUtilMemFree(asnValue
.object
.ids
);
564 SnmpUtilMemFree(asnValue
.sequence
.stream
);
567 SnmpUtilMemFree(asnValue
.address
.stream
);
571 SnmpUtilMemFree(asnValue
.arbitrary
.stream
);
576 asnType
= ASN_INTEGER
;
580 BOOL
PWin32AsnAny::GetInteger(AsnInteger
& i
)
582 if (asnType
!= ASN_INTEGER
)
590 BOOL
PWin32AsnAny::GetIpAddress(PIPSocket::Address
& addr
)
592 if (asnType
!= ASN_IPADDRESS
|| asnValue
.address
.stream
== NULL
)
595 addr
= PIPSocket::Address(asnValue
.address
.length
, asnValue
.address
.stream
);
600 ///////////////////////////////////////////////////////////////////////////////
602 PWin32AsnOid::PWin32AsnOid()
609 PWin32AsnOid::PWin32AsnOid(const char * str
)
614 AsnObjectIdentifier oid
;
616 const char * dot
= strchr(str
, '.');
617 while (dot
!= NULL
) {
619 dot
= strchr(dot
+1, '.');
622 if (oid
.idLength
> 0) {
623 oid
.ids
= new UINT
[++oid
.idLength
];
624 char * next
= (char *)str
;
625 for (UINT i
= 0; i
< oid
.idLength
; i
++) {
626 oid
.ids
[i
] = strtoul(next
, &next
, 10);
633 SnmpUtilOidCpy(this, &oid
);
640 PWin32AsnOid
& PWin32AsnOid::operator=(const AsnObjectIdentifier
& oid
)
643 idLength
= oid
.idLength
;
648 ///////////////////////////////////////////////////////////////////////////////
651 PWin32SnmpLibrary::PWin32SnmpLibrary()
653 : PDynaLink("inetmib1.dll")
658 AsnObjectIdentifier baseOid
;
659 if (!GetFunction("SnmpExtensionInit", (Function
&)_Init
) ||
660 !GetFunction("SnmpExtensionQuery", (Function
&)_Query
)) {
662 PTRACE(1, "PWlib\tInvalid DLL: inetmib1.dll");
664 else if (!Init(0, &hEvent
, &baseOid
)) {
665 PTRACE(1, "PWlib\tCould not initialise SNMP DLL: error=" << ::GetLastError());
670 Init
= SnmpExtensionInit
; // do not call Init as we dont'have Close
671 Query
= SnmpExtensionQuery
;
675 BOOL
PWin32SnmpLibrary::GetOid(AsnObjectIdentifier
& oid
, AsnInteger
& value
)
681 if (!GetOid(oid
, any
))
684 return any
.GetInteger(value
);
688 BOOL
PWin32SnmpLibrary::GetOid(AsnObjectIdentifier
& oid
, PIPSocket::Address
& value
)
694 if (!GetOid(oid
, any
))
697 return any
.GetIpAddress(value
);
701 BOOL
PWin32SnmpLibrary::GetOid(AsnObjectIdentifier
& oid
, PString
& str
)
707 if (!GetOid(oid
, any
))
710 if (any
.asnType
!= ASN_OCTETSTRING
)
713 str
= PString((char *)any
.asnValue
.string
.stream
, any
.asnValue
.string
.length
);
718 BOOL
PWin32SnmpLibrary::GetOid(AsnObjectIdentifier
& oid
, void * value
, UINT valSize
, UINT
* len
)
724 if (!GetOid(oid
, any
))
727 if (any
.asnType
!= ASN_OCTETSTRING
)
731 *len
= any
.asnValue
.string
.length
;
733 if (any
.asnValue
.string
.length
> valSize
)
736 memcpy(value
, any
.asnValue
.string
.stream
, any
.asnValue
.string
.length
);
737 if (valSize
> any
.asnValue
.string
.length
)
738 ((char *)value
)[any
.asnValue
.string
.length
] = '\0';
743 BOOL
PWin32SnmpLibrary::QueryOid(BYTE cmd
, AsnObjectIdentifier
& oid
, PWin32AsnAny
& value
)
750 SnmpVarBindList vars
;
752 vars
.list
= (SnmpVarBind
*)SnmpUtilMemAlloc(sizeof(SnmpVarBind
));
753 if (vars
.list
== NULL
)
756 vars
.list
->name
= oid
;
757 vars
.list
->value
= value
;
759 AsnInteger status
, error
;
760 if (Query(cmd
, &vars
, &status
, &error
) && status
== SNMP_ERRORSTATUS_NOERROR
) {
761 (AsnAny
&)value
= vars
.list
->value
; // Use cast so does simple copy
762 oid
= vars
.list
->name
;
765 SnmpUtilMemFree(vars
.list
);
767 return status
== SNMP_ERRORSTATUS_NOERROR
;
771 PString
PWin32SnmpLibrary::GetInterfaceName(int ifNum
)
773 PIPSocket::Address gwAddr
= 0;
774 PWin32AsnOid baseOid
= "1.3.6.1.2.1.4.20.1";
775 PWin32AsnOid oid
= baseOid
;
777 while (GetNextOid(oid
, value
)) {
778 if (!(baseOid
*= oid
))
780 if (value
.asnType
!= ASN_IPADDRESS
)
784 AsnInteger ifIndex
= -1;
785 if (!GetOid(oid
, ifIndex
) || ifIndex
< 0)
788 if (ifIndex
== ifNum
) {
789 value
.GetIpAddress(gwAddr
);
797 return PString::Empty();
799 PString name
= GetInterfaceName(gwAddr
);
800 if (name
.IsEmpty()) {
801 PWin32AsnOid nameOid
= "1.3.6.1.2.1.2.2.1.2.0";
803 if (GetOid(nameOid
, name
.GetPointer(100), 100))
804 name
.MakeMinimumSize();
811 PString
PWin32SnmpLibrary::GetInterfaceName(PIPSocket::Address ipAddr
)
813 PString gatewayInterface
, anInterface
;
815 PWin32PacketDriver
* tempDriver
= PWin32PacketDriver::Create();
818 while (gatewayInterface
.IsEmpty() && tempDriver
->EnumInterfaces(ifIdx
++, anInterface
)) {
819 if (tempDriver
->BindInterface(anInterface
)) {
820 PIPSocket::Address ifAddr
, ifMask
;
822 if (tempDriver
->EnumIpAddress(ipIdx
++, ifAddr
, ifMask
) && ifAddr
== ipAddr
) {
823 gatewayInterface
= anInterface
;
831 return gatewayInterface
;
836 PWin32SnmpLibrary & PWin32SnmpLibrary::Current()
838 static PWin32SnmpLibrary instance;
843 ///////////////////////////////////////////////////////////////////////////////
845 PWin32OidBuffer::PWin32OidBuffer(UINT oid
, UINT len
, const BYTE
* data
)
847 size
= sizeof(DWORD
)*2 + len
;
848 buffer
= new DWORD
[(size
+sizeof(DWORD
)-1)/sizeof(DWORD
)];
853 memcpy(&buffer
[2], data
, len
);
857 void PWin32OidBuffer::Move(BYTE
* data
, DWORD received
)
859 memcpy(data
, &buffer
[2], received
-sizeof(DWORD
)*2);
863 ///////////////////////////////////////////////////////////////////////////////
865 PWin32PacketDriver
* PWin32PacketDriver::Create()
868 info
.dwOSVersionInfoSize
= sizeof(info
);
871 if (info
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
872 return new PWin32PacketSYS
;
874 return new PWin32PacketVxD
;
876 return new PWin32PacketCe
;
881 PWin32PacketDriver::PWin32PacketDriver()
883 hDriver
= INVALID_HANDLE_VALUE
;
884 dwError
= ERROR_OPEN_FAILED
;
888 PWin32PacketDriver::~PWin32PacketDriver()
894 void PWin32PacketDriver::Close()
896 if (hDriver
!= INVALID_HANDLE_VALUE
) {
897 CloseHandle(hDriver
);
898 hDriver
= INVALID_HANDLE_VALUE
;
903 BOOL
PWin32PacketDriver::IsOpen() const
905 return hDriver
!= INVALID_HANDLE_VALUE
;
909 DWORD
PWin32PacketDriver::GetLastError() const
915 BOOL
PWin32PacketDriver::IoControl(UINT func
,
916 const void * input
, DWORD inSize
,
917 void * output
, DWORD outSize
, DWORD
& received
)
919 PWin32Overlapped overlap
;
921 if (DeviceIoControl(hDriver
, func
,
922 (LPVOID
)input
, inSize
, output
, outSize
,
923 &received
, &overlap
)) {
924 dwError
= ERROR_SUCCESS
;
928 dwError
= ::GetLastError();
929 if (dwError
!= ERROR_IO_PENDING
)
932 return CompleteIO(received
, overlap
);
935 BOOL
PWin32PacketDriver::CompleteIO(DWORD
& received
, PWin32Overlapped
& overlap
)
939 if (GetOverlappedResult(hDriver
, &overlap
, &received
, TRUE
)) {
940 dwError
= ERROR_SUCCESS
;
944 dwError
= ::GetLastError();
951 BOOL
PWin32PacketDriver::QueryOid(UINT oid
, UINT len
, BYTE
* data
)
953 PWin32OidBuffer
buf(oid
, len
);
955 if (!IoControl(GetQueryOidCommand(oid
), buf
, buf
, buf
, buf
, rxsize
))
961 buf
.Move(data
, rxsize
);
966 BOOL
PWin32PacketDriver::QueryOid(UINT oid
, DWORD
& data
)
970 oidData
[1] = sizeof(data
);
971 oidData
[2] = 0x12345678;
974 if (!IoControl(GetQueryOidCommand(oid
),
975 oidData
, sizeof(oidData
),
976 oidData
, sizeof(oidData
),
988 BOOL
PWin32PacketDriver::SetOid(UINT oid
, UINT len
, const BYTE
* data
)
991 PWin32OidBuffer
buf(oid
, len
, data
);
992 return IoControl(IOCTL_EPACKET_SET_OID
, buf
, buf
, buf
, buf
, rxsize
);
996 BOOL
PWin32PacketDriver::SetOid(UINT oid
, DWORD data
)
1000 oidData
[1] = sizeof(data
);
1003 return IoControl(IOCTL_EPACKET_SET_OID
,
1004 oidData
, sizeof(oidData
), oidData
, sizeof(oidData
), rxsize
);
1007 static BOOL
RegistryQueryMultiSz(RegistryKey
& registry
,
1008 const PString
& variable
,
1013 if (!registry
.QueryValue(variable
, allValues
))
1016 const char * ptr
= allValues
;
1017 while (*ptr
!= '\0' && idx
-- > 0)
1018 ptr
+= strlen(ptr
)+1;
1028 ///////////////////////////////////////////////////////////////////////////////
1030 BOOL
PWin32PacketVxD::EnumInterfaces(PINDEX idx
, PString
& name
)
1032 static const PString RegBase
= SERVICES_REGISTRY_KEY
"Class\\Net";
1035 RegistryKey
registry(RegBase
, RegistryKey::ReadOnly
);
1036 if (!registry
.EnumKey(idx
, keyName
))
1039 PString description
;
1040 RegistryKey
subkey(RegBase
+ "\\" + keyName
, RegistryKey::ReadOnly
);
1041 if (subkey
.QueryValue("DriverDesc", description
))
1042 name
= keyName
+ ": " + description
;
1050 static PString
SearchRegistryKeys(const PString
& key
,
1051 const PString
& variable
,
1052 const PString
& value
)
1054 RegistryKey
registry(key
, RegistryKey::ReadOnly
);
1057 if (registry
.QueryValue(variable
, str
) && (str
*= value
))
1060 for (PINDEX idx
= 0; registry
.EnumKey(idx
, str
); idx
++) {
1061 PString result
= SearchRegistryKeys(key
+ str
+ '\\', variable
, value
);
1066 return PString::Empty();
1070 BOOL
PWin32PacketVxD::BindInterface(const PString
& interfaceName
)
1076 if (hDriver
== INVALID_HANDLE_VALUE
) {
1077 hDriver
= CreateFile("\\\\.\\" PACKET_VXD_NAME
".VXD",
1078 GENERIC_READ
| GENERIC_WRITE
,
1082 FILE_ATTRIBUTE_NORMAL
|
1083 FILE_FLAG_OVERLAPPED
|
1084 FILE_FLAG_DELETE_ON_CLOSE
,
1086 if (hDriver
== INVALID_HANDLE_VALUE
) {
1087 dwError
= ::GetLastError();
1093 if (!IoControl(IOCTL_EPACKET_VERSION
, NULL
, 0, buf
, sizeof(buf
), rxsize
)) {
1094 dwError
= ::GetLastError();
1098 if (rxsize
!= 2 || buf
[0] < 1 || buf
[1] < 1) { // Require driver version 1.1
1100 dwError
= ERROR_BAD_DRIVER
;
1107 PINDEX colon
= interfaceName
.Find(':');
1108 if (colon
!= P_MAX_INDEX
)
1109 devName
= interfaceName
.Left(colon
);
1111 devName
= interfaceName
;
1114 if (!IoControl(IOCTL_EPACKET_BIND
,
1115 (const char *)devName
, devName
.GetLength()+1,
1116 buf
, sizeof(buf
), rxsize
) || rxsize
== 0) {
1117 dwError
= ::GetLastError();
1119 dwError
= ERROR_BAD_DRIVER
;
1123 // Get a random OID to verify that the driver did actually open
1124 if (!QueryOid(OID_GEN_DRIVER_VERSION
, 2, buf
))
1127 dwError
= ERROR_SUCCESS
; // Successful, even if may not be bound.
1129 PString devKey
= SearchRegistryKeys("HKEY_LOCAL_MACHINE\\Enum\\", "Driver", "Net\\" + devName
);
1130 if (devKey
.IsEmpty())
1133 RegistryKey
bindRegistry(devKey
+ "Bindings", RegistryKey::ReadOnly
);
1136 while (bindRegistry
.EnumValue(idx
++, binding
)) {
1137 if (binding
.Left(6) *= "MSTCP\\") {
1138 RegistryKey
mstcpRegistry("HKEY_LOCAL_MACHINE\\Enum\\Network\\" + binding
, RegistryKey::ReadOnly
);
1140 if (mstcpRegistry
.QueryValue("Driver", str
))
1141 transportBinding
.AppendString(SERVICES_REGISTRY_KEY
"Class\\" + str
);
1144 #endif // !_WIN32_WCE
1149 BOOL
PWin32PacketVxD::EnumIpAddress(PINDEX idx
,
1150 PIPSocket::Address
& addr
,
1151 PIPSocket::Address
& net_mask
)
1153 if (idx
>= transportBinding
.GetSize())
1156 RegistryKey
transportRegistry(transportBinding
[idx
], RegistryKey::ReadOnly
);
1158 if (transportRegistry
.QueryValue("IPAddress", str
))
1164 if (addr
.GetVersion() == 6) {
1166 // Seb: Something to do ?
1168 if (transportRegistry
.QueryValue("IPMask", str
))
1171 if (IN_CLASSA(addr
))
1172 net_mask
= "255.0.0.0";
1173 else if (IN_CLASSB(addr
))
1174 net_mask
= "255.255.0.0";
1175 else if (IN_CLASSC(addr
))
1176 net_mask
= "255.255.255.0";
1184 PEthSocket::Address macAddress
;
1185 if (!QueryOid(OID_802_3_CURRENT_ADDRESS
, sizeof(macAddress
), macAddress
.b
))
1189 for (dhcpCount
= 0; dhcpCount
< 8; dhcpCount
++) {
1190 RegistryKey
dhcpRegistry(psprintf(SERVICES_REGISTRY_KEY
"VxD\\DHCP\\DhcpInfo%02u", dhcpCount
),
1191 RegistryKey::ReadOnly
);
1192 if (dhcpRegistry
.QueryValue("DhcpInfo", str
)) {
1195 PIPSocket::Address ipAddress
;
1196 PIPSocket::Address mask
;
1197 PIPSocket::Address server
;
1198 PIPSocket::Address anotherAddress
;
1206 PEthSocket::Address macAddress
;
1207 } * dhcpInfo
= (DhcpInfo
*)(const char *)str
;
1208 if (dhcpInfo
->macAddress
== macAddress
) {
1209 addr
= dhcpInfo
->ipAddress
;
1210 net_mask
= dhcpInfo
->mask
;
1214 else if (dhcpRegistry
.QueryValue("HardwareAddress", str
) &&
1215 str
.GetSize() >= sizeof(PEthSocket::Address
)) {
1216 PEthSocket::Address hardwareAddress
;
1217 memcpy(&hardwareAddress
, (const char *)str
, sizeof(hardwareAddress
));
1218 if (hardwareAddress
== macAddress
) {
1219 if (dhcpRegistry
.QueryValue("DhcpIPAddress", str
) &&
1220 str
.GetSize() >= sizeof(addr
)) {
1221 memcpy(&addr
, (const char *)str
, sizeof(addr
));
1222 if (dhcpRegistry
.QueryValue("DhcpSubnetMask", str
) &&
1223 str
.GetSize() >= sizeof(net_mask
)) {
1224 memcpy(&net_mask
, (const char *)str
, sizeof(net_mask
));
1236 BOOL
PWin32PacketVxD::BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
)
1239 if (DeviceIoControl(hDriver
, IOCTL_EPACKET_READ
,
1240 buf
, size
, buf
, size
, &received
, &overlap
)) {
1241 dwError
= ERROR_SUCCESS
;
1245 dwError
= ::GetLastError();
1246 return dwError
== ERROR_IO_PENDING
;
1250 BOOL
PWin32PacketVxD::BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
)
1254 if (DeviceIoControl(hDriver
, IOCTL_EPACKET_WRITE
,
1255 (void *)buf
, len
, dummy
, sizeof(dummy
), &rxsize
, &overlap
)) {
1256 dwError
= ERROR_SUCCESS
;
1260 dwError
= ::GetLastError();
1261 return dwError
== ERROR_IO_PENDING
;
1265 ///////////////////////////////////////////////////////////////////////////////
1267 PWin32PacketSYS::PWin32PacketSYS()
1270 // Start the packet driver service
1271 SC_HANDLE hManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1272 if (hManager
!= NULL
) {
1273 SC_HANDLE hService
= OpenService(hManager
, PACKET_SERVICE_NAME
, SERVICE_START
);
1274 if (hService
!= NULL
) {
1275 StartService(hService
, 0, NULL
);
1276 dwError
= ::GetLastError();
1277 CloseServiceHandle(hService
);
1279 CloseServiceHandle(hManager
);
1281 #endif // !_WIN32_WCE
1285 static const char PacketDeviceStr
[] = "\\Device\\" PACKET_SERVICE_NAME
"_";
1287 BOOL
PWin32PacketSYS::EnumInterfaces(PINDEX idx
, PString
& name
)
1290 RegistryKey
registry(SERVICES_REGISTRY_KEY PACKET_SERVICE_NAME
"\\Linkage",
1291 RegistryKey::ReadOnly
);
1292 if (!RegistryQueryMultiSz(registry
, "Export", idx
, name
)) {
1293 dwError
= ERROR_NO_MORE_ITEMS
;
1297 if (strnicmp(name
, PacketDeviceStr
, sizeof(PacketDeviceStr
)-1) == 0)
1298 name
.Delete(0, sizeof(PacketDeviceStr
)-1);
1300 #endif // !_WIN32_WCE
1305 BOOL
PWin32PacketSYS::BindInterface(const PString
& interfaceName
)
1310 if (!DefineDosDevice(DDD_RAW_TARGET_PATH
,
1311 PACKET_SERVICE_NAME
"_" + interfaceName
,
1312 PacketDeviceStr
+ interfaceName
)) {
1313 dwError
= ::GetLastError();
1318 hDriver
= CreateFile("\\\\.\\" PACKET_SERVICE_NAME
"_" + interfaceName
,
1319 GENERIC_READ
| GENERIC_WRITE
,
1323 FILE_FLAG_OVERLAPPED
,
1325 if (hDriver
== INVALID_HANDLE_VALUE
) {
1326 dwError
= ::GetLastError();
1330 registryKey
= SERVICES_REGISTRY_KEY
+ interfaceName
+ "\\Parameters\\Tcpip";
1331 dwError
= ERROR_SUCCESS
;
1333 #endif // !_WIN32_WCE
1338 BOOL
PWin32PacketSYS::EnumIpAddress(PINDEX idx
,
1339 PIPSocket::Address
& addr
,
1340 PIPSocket::Address
& net_mask
)
1343 RegistryKey
registry(registryKey
, RegistryKey::ReadOnly
);
1345 if (!RegistryQueryMultiSz(registry
, "IPAddress", idx
, str
)) {
1346 dwError
= ERROR_NO_MORE_ITEMS
;
1351 if (!RegistryQueryMultiSz(registry
, "SubnetMask", idx
, str
)) {
1352 dwError
= ERROR_NO_MORE_ITEMS
;
1361 BOOL
PWin32PacketSYS::BeginRead(void * buf
, DWORD size
, DWORD
& received
, PWin32Overlapped
& overlap
)
1366 if (ReadFile(hDriver
, buf
, size
, &received
, &overlap
)) {
1367 dwError
= ERROR_SUCCESS
;
1371 return (dwError
= ::GetLastError()) == ERROR_IO_PENDING
;
1375 BOOL
PWin32PacketSYS::BeginWrite(const void * buf
, DWORD len
, PWin32Overlapped
& overlap
)
1379 if (WriteFile(hDriver
, buf
, len
, &sent
, &overlap
)) {
1380 dwError
= ERROR_SUCCESS
;
1384 dwError
= ::GetLastError();
1385 return dwError
== ERROR_IO_PENDING
;
1388 ///////////////////////////////////////////////////////////////////////////////
1391 PWin32PacketCe::PWin32PacketCe()
1393 PString str
, driver
, nameStr
, keyStr
, driverStr
,
1394 miniportStr
, linkageStr
, routeStr
, tcpipStr
;
1396 static const PString ActiveDrivers
= "HKEY_LOCAL_MACHINE\\Drivers\\Active";
1397 static const PString CommBase
= "HKEY_LOCAL_MACHINE\\Comm";
1399 // Collecting active drivers
1400 RegistryKey
registry(ActiveDrivers
, RegistryKey::ReadOnly
);
1401 for (PINDEX idx
= 0; registry
.EnumKey(idx
, str
); idx
++)
1403 driver
= ActiveDrivers
+ "\\" + str
;
1404 RegistryKey
driverKey( driver
, RegistryKey::ReadOnly
);
1406 // Filter out non - NDS drivers
1407 if( !driverKey
.QueryValue( "Name", nameStr
) ||
1408 nameStr
.Find("NDS") == P_MAX_INDEX
)
1411 // Active network driver found
1413 // e.g. built-in driver has "Key" = Drivers\BuiltIn\NDIS
1414 if( driverKey
.QueryValue( "Key", keyStr
) )
1416 if( P_MAX_INDEX
!= keyStr
.Find("BuiltIn") )
1418 // Built-in driver case
1423 driverStr
= "HKEY_LOCAL_MACHINE\\"+ keyStr
;
1424 RegistryKey
ActiveDriverKey( driverStr
, RegistryKey::ReadOnly
);
1426 // Get miniport value
1427 if( ActiveDriverKey
.QueryValue( "Miniport", miniportStr
) )
1429 // Get miniport linkage
1431 // e.g. [HKEY_LOCAL_MACHINE\Comm\SOCKETLPE\Linkage]
1432 linkageStr
= CommBase
+ "\\" + miniportStr
+ "\\Linkage";
1434 RegistryKey
LinkageKey( linkageStr
, RegistryKey::ReadOnly
);
1436 // Get route to real driver
1437 if( LinkageKey
.QueryValue( "Route", routeStr
) )
1439 tcpipStr
= CommBase
+ "\\" + routeStr
+ "\\Parms\\TcpIp";
1441 RegistryKey
TcpIpKey( tcpipStr
, RegistryKey::ReadOnly
);
1443 DWORD dwDHCPEnabled
= FALSE
;
1444 TcpIpKey
.QueryValue( "EnableDHCP", dwDHCPEnabled
, TRUE
);
1446 /// Collect IP addresses and net masks
1447 PString ipAddress
, netMask
;
1448 if( !dwDHCPEnabled
)
1450 if(TcpIpKey
.QueryValue( "IpAddress", ipAddress
)
1451 && (ipAddress
!= "0.0.0.0") )
1453 interfaces
[interfaces
.GetSize()] = tcpipStr
; // Registry key for the driver
1454 ipAddresses
[ipAddresses
.GetSize()] = ipAddress
; // It's IP
1455 if( driverKey
.QueryValue( "Subnetmask", netMask
) )
1456 netMasks
[netMasks
.GetSize()] = netMask
; // It's mask
1458 netMasks
[netMasks
.GetSize()] = "255.255.255.0";
1461 else // DHCP enabled
1462 if( TcpIpKey
.QueryValue( "DhcpIpAddress", ipAddress
)
1463 && (ipAddress
!= "0.0.0.0") )
1465 interfaces
[interfaces
.GetSize()] = str
;
1466 ipAddresses
[ipAddresses
.GetSize()] = ipAddress
;
1467 if( driverKey
.QueryValue( "DhcpSubnetMask", netMask
) )
1468 netMasks
[netMasks
.GetSize()] = netMask
;
1470 netMasks
[netMasks
.GetSize()] = "255.255.255.0";
1479 BOOL
PWin32PacketCe::EnumInterfaces(PINDEX idx
, PString
& name
)
1481 if( idx
>= interfaces
.GetSize() )
1484 name
= interfaces
[idx
];
1489 BOOL
PWin32PacketCe::BindInterface(const PString
&)
1495 BOOL
PWin32PacketCe::EnumIpAddress(PINDEX idx
,
1496 PIPSocket::Address
& addr
,
1497 PIPSocket::Address
& net_mask
)
1499 if( idx
>= interfaces
.GetSize() )
1502 addr
= ipAddresses
[idx
];
1503 net_mask
= netMasks
[idx
];
1508 BOOL
PWin32PacketCe::BeginRead(void *, DWORD
, DWORD
& , PWin32Overlapped
&)
1514 BOOL
PWin32PacketCe::BeginWrite(const void *, DWORD
, PWin32Overlapped
&)
1519 #endif // _WIN32_WCE
1521 ///////////////////////////////////////////////////////////////////////////////
1523 PEthSocket::PEthSocket(PINDEX nReadBuffers
, PINDEX nWriteBuffers
, PINDEX size
)
1524 : readBuffers(min(nReadBuffers
, MAXIMUM_WAIT_OBJECTS
)),
1525 writeBuffers(min(nWriteBuffers
, MAXIMUM_WAIT_OBJECTS
))
1527 driver
= PWin32PacketDriver::Create();
1529 for (i
= 0; i
< nReadBuffers
; i
++)
1530 readBuffers
.SetAt(i
, new PWin32PacketBuffer(size
));
1531 for (i
= 0; i
< nWriteBuffers
; i
++)
1532 writeBuffers
.SetAt(i
, new PWin32PacketBuffer(size
));
1534 filterType
= TypeAll
;
1538 PEthSocket::~PEthSocket()
1546 BOOL
PEthSocket::OpenSocket()
1548 PAssertAlways(PUnimplementedFunction
);
1553 BOOL
PEthSocket::Close()
1561 PString
PEthSocket::GetName() const
1563 return interfaceName
;
1567 BOOL
PEthSocket::Connect(const PString
& newName
)
1571 if (!driver
->BindInterface(newName
))
1572 return SetErrorValues(Miscellaneous
, driver
->GetLastError()|PWIN32ErrorFlag
);
1574 interfaceName
= newName
;
1580 BOOL
PEthSocket::EnumInterfaces(PINDEX idx
, PString
& name
)
1582 return driver
->EnumInterfaces(idx
, name
);
1586 BOOL
PEthSocket::GetAddress(Address
& addr
)
1588 if (driver
->QueryOid(OID_802_3_CURRENT_ADDRESS
, sizeof(addr
), addr
.b
))
1591 return SetErrorValues(Miscellaneous
, driver
->GetLastError()|PWIN32ErrorFlag
);
1595 BOOL
PEthSocket::EnumIpAddress(PINDEX idx
,
1596 PIPSocket::Address
& addr
,
1597 PIPSocket::Address
& net_mask
)
1600 if (driver
->EnumIpAddress(idx
, addr
, net_mask
))
1603 return SetErrorValues(NotFound
, ENOENT
);
1606 return SetErrorValues(NotOpen
, EBADF
);
1610 static const struct {
1614 { PEthSocket::FilterDirected
, NDIS_PACKET_TYPE_DIRECTED
},
1615 { PEthSocket::FilterMulticast
, NDIS_PACKET_TYPE_MULTICAST
},
1616 { PEthSocket::FilterAllMulticast
, NDIS_PACKET_TYPE_ALL_MULTICAST
},
1617 { PEthSocket::FilterBroadcast
, NDIS_PACKET_TYPE_BROADCAST
},
1618 { PEthSocket::FilterPromiscuous
, NDIS_PACKET_TYPE_PROMISCUOUS
}
1622 BOOL
PEthSocket::GetFilter(unsigned & mask
, WORD
& type
)
1625 return SetErrorValues(NotOpen
, EBADF
);
1628 if (!driver
->QueryOid(OID_GEN_CURRENT_PACKET_FILTER
, filter
))
1629 return SetErrorValues(Miscellaneous
, driver
->GetLastError()|PWIN32ErrorFlag
);
1632 return PEthSocket::FilterDirected
;
1635 for (PINDEX i
= 0; i
< PARRAYSIZE(FilterMasks
); i
++) {
1636 if ((filter
&FilterMasks
[i
].ndis
) != 0)
1637 mask
|= FilterMasks
[i
].pwlib
;
1640 type
= (WORD
)filterType
;
1645 BOOL
PEthSocket::SetFilter(unsigned filter
, WORD type
)
1648 return SetErrorValues(NotOpen
, EBADF
);
1651 for (PINDEX i
= 0; i
< PARRAYSIZE(FilterMasks
); i
++) {
1652 if ((filter
&FilterMasks
[i
].pwlib
) != 0)
1653 bits
|= FilterMasks
[i
].ndis
;
1656 if (!driver
->SetOid(OID_GEN_CURRENT_PACKET_FILTER
, bits
))
1657 return SetErrorValues(Miscellaneous
, driver
->GetLastError()|PWIN32ErrorFlag
);
1664 PEthSocket::MediumTypes
PEthSocket::GetMedium()
1667 SetErrorValues(NotOpen
, EBADF
);
1668 return NumMediumTypes
;
1671 DWORD medium
= 0xffffffff;
1672 if (!driver
->QueryOid(OID_GEN_MEDIA_SUPPORTED
, medium
) || medium
== 0xffffffff) {
1673 SetErrorValues(Miscellaneous
, driver
->GetLastError()|PWIN32ErrorFlag
);
1674 return NumMediumTypes
;
1677 static const DWORD MediumValues
[NumMediumTypes
] = {
1678 0xffffffff, NdisMedium802_3
, NdisMediumWan
, 0xffffffff
1681 for (int type
= Medium802_3
; type
< NumMediumTypes
; type
++) {
1682 if (MediumValues
[type
] == medium
)
1683 return (MediumTypes
)type
;
1686 return MediumUnknown
;
1690 BOOL
PEthSocket::Read(void * data
, PINDEX length
)
1693 return SetErrorValues(NotOpen
, EBADF
, LastReadError
);
1696 PINDEX numBuffers
= readBuffers
.GetSize();
1699 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
1701 for (idx
= 0; idx
< numBuffers
; idx
++) {
1702 PWin32PacketBuffer
& buffer
= readBuffers
[idx
];
1703 if (buffer
.InProgress()) {
1704 if (WaitForSingleObject(buffer
.GetEvent(), 0) == WAIT_OBJECT_0
)
1705 if (!buffer
.ReadComplete(*driver
))
1706 return ConvertOSError(-1, LastReadError
);
1709 if (!buffer
.ReadAsync(*driver
))
1710 return ConvertOSError(-1, LastReadError
);
1713 if (buffer
.IsCompleted() && buffer
.IsType(filterType
)) {
1714 lastReadCount
= buffer
.GetData(data
, length
);
1718 handles
[idx
] = buffer
.GetEvent();
1722 PINDEX retries
= 100;
1724 result
= WaitForMultipleObjects(numBuffers
, handles
, FALSE
, INFINITE
);
1725 if (result
>= WAIT_OBJECT_0
&& result
< WAIT_OBJECT_0
+ (DWORD
)numBuffers
)
1728 if (::GetLastError() != ERROR_INVALID_HANDLE
|| retries
== 0)
1729 return ConvertOSError(-1, LastReadError
);
1734 idx
= result
- WAIT_OBJECT_0
;
1735 if (!readBuffers
[idx
].ReadComplete(*driver
))
1736 return ConvertOSError(-1, LastReadError
);
1738 } while (!readBuffers
[idx
].IsType(filterType
));
1740 lastReadCount
= readBuffers
[idx
].GetData(data
, length
);
1745 BOOL
PEthSocket::Write(const void * data
, PINDEX length
)
1748 return SetErrorValues(NotOpen
, EBADF
, LastWriteError
);
1750 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
1751 PINDEX numBuffers
= writeBuffers
.GetSize();
1754 for (idx
= 0; idx
< numBuffers
; idx
++) {
1755 PWin32PacketBuffer
& buffer
= writeBuffers
[idx
];
1756 if (buffer
.InProgress()) {
1757 if (WaitForSingleObject(buffer
.GetEvent(), 0) == WAIT_OBJECT_0
)
1758 if (!buffer
.WriteComplete(*driver
))
1759 return ConvertOSError(-1, LastWriteError
);
1762 if (!buffer
.InProgress()) {
1763 lastWriteCount
= buffer
.PutData(data
, length
);
1764 return ConvertOSError(buffer
.WriteAsync(*driver
) ? 0 : -1, LastWriteError
);
1767 handles
[idx
] = buffer
.GetEvent();
1770 DWORD result
= WaitForMultipleObjects(numBuffers
, handles
, FALSE
, INFINITE
);
1771 if (result
< WAIT_OBJECT_0
|| result
>= WAIT_OBJECT_0
+ (DWORD
) numBuffers
)
1772 return ConvertOSError(-1, LastWriteError
);
1774 idx
= result
- WAIT_OBJECT_0
;
1775 if (!writeBuffers
[idx
].WriteComplete(*driver
))
1776 return ConvertOSError(-1, LastWriteError
);
1778 lastWriteCount
= writeBuffers
[idx
].PutData(data
, length
);
1779 return ConvertOSError(writeBuffers
[idx
].WriteAsync(*driver
) ? 0 : -1, LastWriteError
);
1783 ///////////////////////////////////////////////////////////////////////////////
1785 PWin32PacketBuffer::PWin32PacketBuffer(PINDEX sz
)
1788 status
= Uninitialised
;
1793 PINDEX
PWin32PacketBuffer::GetData(void * buf
, PINDEX size
)
1795 if (count
> (DWORD
)size
)
1798 memcpy(buf
, theArray
, count
);
1804 PINDEX
PWin32PacketBuffer::PutData(const void * buf
, PINDEX length
)
1806 count
= min(GetSize(), length
);
1808 memcpy(theArray
, buf
, count
);
1814 BOOL
PWin32PacketBuffer::ReadAsync(PWin32PacketDriver
& pkt
)
1816 if (status
== Progressing
)
1819 status
= Uninitialised
;
1820 if (!pkt
.BeginRead(theArray
, GetSize(), count
, overlap
))
1823 if (pkt
.GetLastError() == ERROR_SUCCESS
)
1826 status
= Progressing
;
1831 BOOL
PWin32PacketBuffer::ReadComplete(PWin32PacketDriver
& pkt
)
1833 if (status
!= Progressing
)
1834 return status
== Completed
;
1836 if (!pkt
.CompleteIO(count
, overlap
)) {
1837 status
= Uninitialised
;
1846 BOOL
PWin32PacketBuffer::WriteAsync(PWin32PacketDriver
& pkt
)
1848 if (status
== Progressing
)
1851 status
= Uninitialised
;
1852 if (!pkt
.BeginWrite(theArray
, count
, overlap
))
1855 if (pkt
.GetLastError() == ERROR_SUCCESS
)
1858 status
= Progressing
;
1863 BOOL
PWin32PacketBuffer::WriteComplete(PWin32PacketDriver
& pkt
)
1865 if (status
!= Progressing
)
1866 return status
== Completed
;
1869 if (pkt
.CompleteIO(dummy
, overlap
)) {
1874 status
= Uninitialised
;
1879 BOOL
PWin32PacketBuffer::IsType(WORD filterType
) const
1881 if (filterType
== PEthSocket::TypeAll
)
1884 const PEthSocket::Frame
* frame
= (const PEthSocket::Frame
*)theArray
;
1886 WORD len_or_type
= ntohs(frame
->snap
.length
);
1887 if (len_or_type
> sizeof(*frame
))
1888 return len_or_type
== filterType
;
1890 if (frame
->snap
.dsap
== 0xaa && frame
->snap
.ssap
== 0xaa)
1891 return ntohs(frame
->snap
.type
) == filterType
; // SNAP header
1893 if (frame
->snap
.dsap
== 0xff && frame
->snap
.ssap
== 0xff)
1894 return PEthSocket::TypeIPX
== filterType
; // Special case for Novell netware's stuffed up 802.3
1896 if (frame
->snap
.dsap
== 0xe0 && frame
->snap
.ssap
== 0xe0)
1897 return PEthSocket::TypeIPX
== filterType
; // Special case for Novell netware's 802.2
1899 return frame
->snap
.dsap
== filterType
; // A pure 802.2 protocol id
1902 ///////////////////////////////////////////////////////////////////////////////
1905 static PMutex & GetSNMPMutex()
1907 static PMutex snmpmutex;
1912 BOOL
PIPSocket::GetGatewayAddress(Address
& addr
)
1914 PWaitAndSignal
m(GetSNMPMutex());
1915 PWin32SnmpLibrary
& snmp
= PWin32SnmpLibrary::Current();
1917 PWin32AsnOid gatewayOid
= "1.3.6.1.2.1.4.21.1.7.0.0.0.0";
1918 return snmp
.GetOid(gatewayOid
, addr
);
1922 PString
PIPSocket::GetGatewayInterface()
1924 PWaitAndSignal
m(GetSNMPMutex());
1926 PWin32SnmpLibrary
& snmp
= PWin32SnmpLibrary::Current();
1928 AsnInteger ifNum
= -1;
1929 PWin32AsnOid gatewayOid
= "1.3.6.1.2.1.4.21.1.2.0.0.0.0";
1930 if (!snmp
.GetOid(gatewayOid
, ifNum
) && ifNum
>= 0)
1931 return PString::Empty();
1933 return snmp
.GetInterfaceName(ifNum
);
1937 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1939 PWaitAndSignal
m(GetSNMPMutex());
1941 PWin32SnmpLibrary
& snmp
= snmp
.Current();
1944 PWin32AsnOid baseOid
= "1.3.6.1.2.1.4.21.1";
1945 PWin32AsnOid oid
= baseOid
;
1947 DWORD lastVariable
= 1;
1952 while (snmp
.GetNextOid(oid
, value
) && (baseOid
*= oid
)) {
1953 if (lastVariable
!= oid
[9]) {
1954 lastVariable
= oid
[9];
1955 if (lastVariable
== 2)
1956 ifNum
.SetSize(table
.GetSize());
1960 switch (lastVariable
) {
1961 case 1 : // network address
1964 if (!value
.GetIpAddress(addr
))
1965 return FALSE
; // Very confused route table
1967 table
.Append(new RouteEntry(addr
));
1971 case 2 : // device interface
1972 if (!value
.GetInteger(ifNum
[idx
]))
1977 if (!value
.GetInteger(table
[idx
].metric
))
1981 case 7 : // Get destination (next hop)
1982 if (!value
.GetIpAddress(table
[idx
].destination
))
1986 case 11 : // Get mask
1987 if (!value
.GetIpAddress(table
[idx
].net_mask
))
1995 for (idx
= 0; idx
< table
.GetSize(); idx
++)
1996 table
[idx
].interfaceName
= snmp
.GetInterfaceName(ifNum
[idx
]);
2002 BOOL
PIPSocket::GetInterfaceTable(InterfaceTable
& table
)
2004 PWin32SnmpLibrary
& snmp
= snmp
.Current();
2006 PWaitAndSignal
m(GetSNMPMutex());
2011 if (!snmp.IsLoaded()) {
2012 // Error loading the SNMP library, fail safe to using whatever the
2013 // address of the local host is.
2015 if (!GetHostAddress(ipAddr))
2017 Address netMask(255,255,255,255);
2018 table.Append(new InterfaceEntry("FailSafe Interface", ipAddr, netMask, PString::Empty()));
2019 table.Append(new InterfaceEntry("localhost", PIPSocket::Address(), netMask, PString::Empty()));
2024 PWin32AsnOid baseOid
= "1.3.6.1.2.1.4.20.1";
2025 PWin32AsnOid oid
= baseOid
;
2027 while (snmp
.GetNextOid(oid
, value
)) {
2028 if (!(baseOid
*= oid
))
2030 if (value
.asnType
!= ASN_IPADDRESS
)
2034 value
.GetIpAddress(ipAddr
);
2038 if (!snmp
.GetOid(oid
, netMask
))
2042 AsnInteger ifIndex
= -1;
2043 if (!snmp
.GetOid(oid
, ifIndex
))
2047 PEthSocket::Address
ifPhysAddress("");
2048 PWin32AsnOid ifOid
= "1.3.6.1.2.1.2.2.1.6.0";
2049 ifOid
[10] = ifIndex
;
2051 if (snmp
.GetOid(ifOid
, &ifPhysAddress
, sizeof(ifPhysAddress
), &len
) && len
> 0)
2052 macAddr
= ifPhysAddress
;
2054 PString name
= snmp
.GetInterfaceName(ipAddr
);
2055 if (name
.IsEmpty()) {
2056 PWin32AsnOid nameOid
= "1.3.6.1.2.1.2.2.1.2.0";
2057 nameOid
[10] = ifIndex
;
2058 if (!snmp
.GetOid(nameOid
, name
))
2060 name
.MakeMinimumSize();
2063 #ifdef _WIN32_WCE // Getting rid of ghost ips
2064 if ( !name
.IsEmpty() )
2066 table
.Append(new InterfaceEntry(name
, ipAddr
, netMask
, macAddr
));
2075 ///////////////////////////////////////////////////////////////////////////////