Added PSharedptr class
[pwlib.git] / src / ptlib / msos / ethsock.cxx
blobe73c284d5dc4a0021ea533798a871d712426170d
1 /*
2 * ethsock.cxx
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
89 * no message
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
167 * Initial revision
171 #include <ptlib.h>
172 #include <ptlib/sockets.h>
173 #include <snmp.h>
175 #pragma comment(lib, "snmpapi.lib")
177 ///////////////////////////////////////////////////////////////////////////////
178 // Stuff from snmp.h
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!")
188 #endif
190 ///////////////////////////////////////////////////////////////////////////////
191 // Stuff from ndis.h
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 {
207 NdisMedium802_3,
208 NdisMedium802_5,
209 NdisMediumFddi,
210 NdisMediumWan,
211 NdisMediumLocalTalk,
212 NdisMediumDix, // defined for convenience, not a real medium
213 NdisMediumArcnetRaw,
214 NdisMediumArcnet878_2
215 } NDIS_MEDIUM, *PNDIS_MEDIUM;
217 ///////////////////////////////////////////////////////////////////////////////
220 #define USE_VPACKET
221 #include <ptlib/msos/ptlib/epacket.h>
223 #ifdef USE_VPACKET
224 #define PACKET_SERVICE_NAME "Packet"
225 #define PACKET_VXD_NAME "VPacket"
226 #else
227 #define PACKET_SERVICE_NAME "EPacket"
228 #define PACKET_VXD_NAME "EPacket"
229 #define GetQueryOidCommand(oid) IOCTL_EPACKET_QUERY_OID
230 #endif
232 #define SERVICES_REGISTRY_KEY "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\"
235 ///////////////////////////////////////////////////////////////////////////////
237 class PWin32AsnAny : public AsnAny
239 public:
240 PWin32AsnAny();
241 ~PWin32AsnAny() { MemFree(); }
242 BOOL GetInteger(AsnInteger & i);
243 BOOL GetIpAddress(PIPSocket::Address & addr);
244 void MemFree();
245 private:
246 PWin32AsnAny(const PWin32AsnAny &) { }
247 PWin32AsnAny & operator=(const PWin32AsnAny &) { return *this; }
251 ///////////////////////////////////////////////////////////////////////////////
253 class PWin32AsnOid : public AsnObjectIdentifier
255 public:
256 PWin32AsnOid();
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
278 #ifndef _WIN32_WCE
279 : public PDynaLink
281 PCLASSINFO(PWin32SnmpLibrary, PDynaLink)
282 public:
283 #else
285 public:
286 void Close();
287 BOOL IsLoaded() { return TRUE; }
288 #endif
289 public:
290 PWin32SnmpLibrary();
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();
306 private:
307 PMutex mutex;
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);
324 public:
325 void OnStartup()
328 PWin32SnmpLibrary & Current()
330 PWaitAndSignal m(mutex);
331 if (snmpLibrary == NULL) {
332 snmpLibrary = new PWin32SnmpLibrary;
334 return *snmpLibrary;
337 void OnShutdown()
339 PWaitAndSignal m(mutex);
340 delete snmpLibrary;
341 snmpLibrary = NULL;
344 protected:
345 PMutex 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
369 public:
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);
379 private:
380 DWORD * buffer;
381 UINT size;
385 ///////////////////////////////////////////////////////////////////////////////
387 class PWin32PacketDriver
389 public:
390 static PWin32PacketDriver * Create();
392 virtual ~PWin32PacketDriver();
394 BOOL IsOpen() const;
395 void Close();
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,
410 DWORD & received);
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);
416 #ifdef USE_VPACKET
417 virtual UINT GetQueryOidCommand(DWORD oid) const = 0;
418 #endif
420 protected:
421 PWin32PacketDriver();
423 DWORD dwError;
424 HANDLE hDriver;
427 ///////////////////////////////////////////////////////////////////////////////
429 class PWin32PacketVxD : public PWin32PacketDriver
431 public:
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);
440 #ifdef USE_VPACKET
441 virtual UINT GetQueryOidCommand(DWORD oid) const
442 { return oid >= OID_802_3_PERMANENT_ADDRESS ? IOCTL_EPACKET_QUERY_OID : IOCTL_EPACKET_STATISTICS; }
443 #endif
445 protected:
446 PStringList transportBinding;
450 ///////////////////////////////////////////////////////////////////////////////
452 class PWin32PacketSYS : public PWin32PacketDriver
454 public:
455 PWin32PacketSYS();
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);
465 #ifdef USE_VPACKET
466 virtual UINT GetQueryOidCommand(DWORD) const
467 { return IOCTL_EPACKET_QUERY_OID; }
468 #endif
470 protected:
471 PString registryKey;
474 ///////////////////////////////////////////////////////////////////////////////
476 #ifdef _WIN32_WCE
478 class PWin32PacketCe : public PWin32PacketDriver
480 public:
481 PWin32PacketCe();
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);
491 #ifdef USE_VPACKET
492 virtual UINT GetQueryOidCommand(DWORD) const
493 { return IOCTL_EPACKET_QUERY_OID; }
494 #endif
495 protected:
496 PStringArray ipAddresses;
497 PStringArray netMasks;
498 PStringArray interfaces;
501 #endif // _WIN32_WCE
503 /////////////////////////////////////////////////////////////////////////////
505 class PWin32PacketBuffer : public PBYTEArray
507 PCLASSINFO(PWin32PacketBuffer, PBYTEArray)
508 public:
509 enum Statuses {
510 Uninitialised,
511 Progressing,
512 Completed
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;
530 protected:
531 Statuses status;
532 PWin32Overlapped overlap;
533 DWORD count;
537 #define new PNEW
540 /////////////////////////////////////////////////////////////////////////////
542 PWin32AsnAny::PWin32AsnAny()
544 asnType = ASN_INTEGER;
545 asnValue.number = 0;
549 void PWin32AsnAny::MemFree()
551 switch (asnType) {
552 case ASN_OCTETSTRING :
553 SnmpUtilMemFree(asnValue.string.stream);
554 break;
555 #ifdef ASN_BITS
556 case ASN_BITS :
557 SnmpUtilMemFree(asnValue.bits.stream);
558 break;
559 #endif
560 case ASN_OBJECTIDENTIFIER :
561 SnmpUtilMemFree(asnValue.object.ids);
562 break;
563 case ASN_SEQUENCE :
564 SnmpUtilMemFree(asnValue.sequence.stream);
565 break;
566 case ASN_IPADDRESS :
567 SnmpUtilMemFree(asnValue.address.stream);
568 break;
569 #ifdef ASN_OPAQUE
570 case ASN_OPAQUE :
571 SnmpUtilMemFree(asnValue.arbitrary.stream);
572 break;
573 #endif
576 asnType = ASN_INTEGER;
580 BOOL PWin32AsnAny::GetInteger(AsnInteger & i)
582 if (asnType != ASN_INTEGER)
583 return FALSE;
585 i = asnValue.number;
586 return TRUE;
590 BOOL PWin32AsnAny::GetIpAddress(PIPSocket::Address & addr)
592 if (asnType != ASN_IPADDRESS || asnValue.address.stream == NULL)
593 return FALSE;
595 addr = PIPSocket::Address(asnValue.address.length, asnValue.address.stream);
596 return TRUE;
600 ///////////////////////////////////////////////////////////////////////////////
602 PWin32AsnOid::PWin32AsnOid()
604 ids = NULL;
605 idLength = 0;
609 PWin32AsnOid::PWin32AsnOid(const char * str)
611 idLength = 0;
612 ids = NULL;
614 AsnObjectIdentifier oid;
615 oid.idLength = 0;
616 const char * dot = strchr(str, '.');
617 while (dot != NULL) {
618 oid.idLength++;
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);
627 if (*next != '.')
628 break;
629 next++;
632 if (*next == '\0')
633 SnmpUtilOidCpy(this, &oid);
635 delete [] oid.ids;
640 PWin32AsnOid & PWin32AsnOid::operator=(const AsnObjectIdentifier & oid)
642 ids = oid.ids;
643 idLength = oid.idLength;
644 return *this;
648 ///////////////////////////////////////////////////////////////////////////////
651 PWin32SnmpLibrary::PWin32SnmpLibrary()
652 #ifndef _WIN32_WCE
653 : PDynaLink("inetmib1.dll")
654 #endif
656 #ifndef _WIN32_WCE
657 HANDLE hEvent;
658 AsnObjectIdentifier baseOid;
659 if (!GetFunction("SnmpExtensionInit", (Function &)_Init) ||
660 !GetFunction("SnmpExtensionQuery", (Function &)_Query)) {
661 Close();
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());
666 Close();
669 #else
670 Init = SnmpExtensionInit; // do not call Init as we dont'have Close
671 Query = SnmpExtensionQuery;
672 #endif
675 BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, AsnInteger & value)
677 //if (!IsLoaded())
678 // return FALSE;
680 PWin32AsnAny any;
681 if (!GetOid(oid, any))
682 return FALSE;
684 return any.GetInteger(value);
688 BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, PIPSocket::Address & value)
690 //if (!IsLoaded())
691 // return FALSE;
693 PWin32AsnAny any;
694 if (!GetOid(oid, any))
695 return FALSE;
697 return any.GetIpAddress(value);
701 BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, PString & str)
703 //if (!IsLoaded())
704 // return FALSE;
706 PWin32AsnAny any;
707 if (!GetOid(oid, any))
708 return FALSE;
710 if (any.asnType != ASN_OCTETSTRING)
711 return FALSE;
713 str = PString((char *)any.asnValue.string.stream, any.asnValue.string.length);
714 return TRUE;
718 BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, void * value, UINT valSize, UINT * len)
720 //if (!IsLoaded())
721 // return FALSE;
723 PWin32AsnAny any;
724 if (!GetOid(oid, any))
725 return FALSE;
727 if (any.asnType != ASN_OCTETSTRING)
728 return FALSE;
730 if (len != NULL)
731 *len = any.asnValue.string.length;
733 if (any.asnValue.string.length > valSize)
734 return FALSE;
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';
739 return TRUE;
743 BOOL PWin32SnmpLibrary::QueryOid(BYTE cmd, AsnObjectIdentifier & oid, PWin32AsnAny & value)
745 //if (!IsLoaded())
746 // return FALSE;
748 value.MemFree();
750 SnmpVarBindList vars;
751 vars.len = 1;
752 vars.list = (SnmpVarBind*)SnmpUtilMemAlloc(sizeof(SnmpVarBind));
753 if (vars.list == NULL)
754 return FALSE;
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;
776 PWin32AsnAny value;
777 while (GetNextOid(oid, value)) {
778 if (!(baseOid *= oid))
779 break;
780 if (value.asnType != ASN_IPADDRESS)
781 break;
783 oid[9] = 2;
784 AsnInteger ifIndex = -1;
785 if (!GetOid(oid, ifIndex) || ifIndex < 0)
786 break;
788 if (ifIndex == ifNum) {
789 value.GetIpAddress(gwAddr);
790 break;
793 oid[9] = 1;
796 if (gwAddr == 0)
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";
802 nameOid[10] = ifNum;
803 if (GetOid(nameOid, name.GetPointer(100), 100))
804 name.MakeMinimumSize();
807 return name;
811 PString PWin32SnmpLibrary::GetInterfaceName(PIPSocket::Address ipAddr)
813 PString gatewayInterface, anInterface;
815 PWin32PacketDriver * tempDriver = PWin32PacketDriver::Create();
817 PINDEX ifIdx = 0;
818 while (gatewayInterface.IsEmpty() && tempDriver->EnumInterfaces(ifIdx++, anInterface)) {
819 if (tempDriver->BindInterface(anInterface)) {
820 PIPSocket::Address ifAddr, ifMask;
821 PINDEX ipIdx = 0;
822 if (tempDriver->EnumIpAddress(ipIdx++, ifAddr, ifMask) && ifAddr == ipAddr) {
823 gatewayInterface = anInterface;
824 break;
829 delete tempDriver;
831 return gatewayInterface;
836 PWin32SnmpLibrary & PWin32SnmpLibrary::Current()
838 static PWin32SnmpLibrary instance;
839 return 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)];
850 buffer[0] = oid;
851 buffer[1] = len;
852 if (data != NULL)
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()
867 OSVERSIONINFO info;
868 info.dwOSVersionInfoSize = sizeof(info);
869 GetVersionEx(&info);
870 #ifndef _WIN32_WCE
871 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
872 return new PWin32PacketSYS;
873 else
874 return new PWin32PacketVxD;
875 #else
876 return new PWin32PacketCe;
877 #endif
881 PWin32PacketDriver::PWin32PacketDriver()
883 hDriver = INVALID_HANDLE_VALUE;
884 dwError = ERROR_OPEN_FAILED;
888 PWin32PacketDriver::~PWin32PacketDriver()
890 Close();
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
911 return dwError;
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;
925 return TRUE;
928 dwError = ::GetLastError();
929 if (dwError != ERROR_IO_PENDING)
930 return FALSE;
932 return CompleteIO(received, overlap);
935 BOOL PWin32PacketDriver::CompleteIO(DWORD & received, PWin32Overlapped & overlap)
937 #ifndef _WIN32_WCE
938 received = 0;
939 if (GetOverlappedResult(hDriver, &overlap, &received, TRUE)) {
940 dwError = ERROR_SUCCESS;
941 return TRUE;
944 dwError = ::GetLastError();
945 return FALSE;
946 #else
947 return TRUE;
948 #endif
951 BOOL PWin32PacketDriver::QueryOid(UINT oid, UINT len, BYTE * data)
953 PWin32OidBuffer buf(oid, len);
954 DWORD rxsize = 0;
955 if (!IoControl(GetQueryOidCommand(oid), buf, buf, buf, buf, rxsize))
956 return FALSE;
958 if (rxsize == 0)
959 return FALSE;
961 buf.Move(data, rxsize);
962 return TRUE;
966 BOOL PWin32PacketDriver::QueryOid(UINT oid, DWORD & data)
968 DWORD oidData[3];
969 oidData[0] = oid;
970 oidData[1] = sizeof(data);
971 oidData[2] = 0x12345678;
973 DWORD rxsize = 0;
974 if (!IoControl(GetQueryOidCommand(oid),
975 oidData, sizeof(oidData),
976 oidData, sizeof(oidData),
977 rxsize))
978 return FALSE;
980 if (rxsize == 0)
981 return FALSE;
983 data = oidData[2];
984 return TRUE;
988 BOOL PWin32PacketDriver::SetOid(UINT oid, UINT len, const BYTE * data)
990 DWORD rxsize = 0;
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)
998 DWORD oidData[3];
999 oidData[0] = oid;
1000 oidData[1] = sizeof(data);
1001 oidData[2] = data;
1002 DWORD rxsize;
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,
1009 PINDEX idx,
1010 PString & value)
1012 PString allValues;
1013 if (!registry.QueryValue(variable, allValues))
1014 return FALSE;
1016 const char * ptr = allValues;
1017 while (*ptr != '\0' && idx-- > 0)
1018 ptr += strlen(ptr)+1;
1020 if (*ptr == '\0')
1021 return FALSE;
1023 value = ptr;
1024 return TRUE;
1028 ///////////////////////////////////////////////////////////////////////////////
1030 BOOL PWin32PacketVxD::EnumInterfaces(PINDEX idx, PString & name)
1032 static const PString RegBase = SERVICES_REGISTRY_KEY "Class\\Net";
1034 PString keyName;
1035 RegistryKey registry(RegBase, RegistryKey::ReadOnly);
1036 if (!registry.EnumKey(idx, keyName))
1037 return FALSE;
1039 PString description;
1040 RegistryKey subkey(RegBase + "\\" + keyName, RegistryKey::ReadOnly);
1041 if (subkey.QueryValue("DriverDesc", description))
1042 name = keyName + ": " + description;
1043 else
1044 name = keyName;
1046 return TRUE;
1050 static PString SearchRegistryKeys(const PString & key,
1051 const PString & variable,
1052 const PString & value)
1054 RegistryKey registry(key, RegistryKey::ReadOnly);
1056 PString str;
1057 if (registry.QueryValue(variable, str) && (str *= value))
1058 return key;
1060 for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++) {
1061 PString result = SearchRegistryKeys(key + str + '\\', variable, value);
1062 if (!result)
1063 return result;
1066 return PString::Empty();
1070 BOOL PWin32PacketVxD::BindInterface(const PString & interfaceName)
1072 #ifndef _WIN32_WCE
1073 BYTE buf[20];
1074 DWORD rxsize;
1076 if (hDriver == INVALID_HANDLE_VALUE) {
1077 hDriver = CreateFile("\\\\.\\" PACKET_VXD_NAME ".VXD",
1078 GENERIC_READ | GENERIC_WRITE,
1080 NULL,
1081 OPEN_EXISTING,
1082 FILE_ATTRIBUTE_NORMAL |
1083 FILE_FLAG_OVERLAPPED |
1084 FILE_FLAG_DELETE_ON_CLOSE,
1085 NULL);
1086 if (hDriver == INVALID_HANDLE_VALUE) {
1087 dwError = ::GetLastError();
1088 return FALSE;
1091 #ifndef USE_VPACKET
1092 rxsize = 0;
1093 if (!IoControl(IOCTL_EPACKET_VERSION, NULL, 0, buf, sizeof(buf), rxsize)) {
1094 dwError = ::GetLastError();
1095 return FALSE;
1098 if (rxsize != 2 || buf[0] < 1 || buf[1] < 1) { // Require driver version 1.1
1099 Close();
1100 dwError = ERROR_BAD_DRIVER;
1101 return FALSE;
1103 #endif
1106 PString devName;
1107 PINDEX colon = interfaceName.Find(':');
1108 if (colon != P_MAX_INDEX)
1109 devName = interfaceName.Left(colon);
1110 else
1111 devName = interfaceName;
1113 rxsize = 0;
1114 if (!IoControl(IOCTL_EPACKET_BIND,
1115 (const char *)devName, devName.GetLength()+1,
1116 buf, sizeof(buf), rxsize) || rxsize == 0) {
1117 dwError = ::GetLastError();
1118 if (dwError == 0)
1119 dwError = ERROR_BAD_DRIVER;
1120 return FALSE;
1123 // Get a random OID to verify that the driver did actually open
1124 if (!QueryOid(OID_GEN_DRIVER_VERSION, 2, buf))
1125 return FALSE;
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())
1131 return TRUE;
1133 RegistryKey bindRegistry(devKey + "Bindings", RegistryKey::ReadOnly);
1134 PString binding;
1135 PINDEX idx = 0;
1136 while (bindRegistry.EnumValue(idx++, binding)) {
1137 if (binding.Left(6) *= "MSTCP\\") {
1138 RegistryKey mstcpRegistry("HKEY_LOCAL_MACHINE\\Enum\\Network\\" + binding, RegistryKey::ReadOnly);
1139 PString str;
1140 if (mstcpRegistry.QueryValue("Driver", str))
1141 transportBinding.AppendString(SERVICES_REGISTRY_KEY "Class\\" + str);
1144 #endif // !_WIN32_WCE
1145 return TRUE;
1149 BOOL PWin32PacketVxD::EnumIpAddress(PINDEX idx,
1150 PIPSocket::Address & addr,
1151 PIPSocket::Address & net_mask)
1153 if (idx >= transportBinding.GetSize())
1154 return FALSE;
1156 RegistryKey transportRegistry(transportBinding[idx], RegistryKey::ReadOnly);
1157 PString str;
1158 if (transportRegistry.QueryValue("IPAddress", str))
1159 addr = str;
1160 else
1161 addr = 0;
1163 if (addr != 0) {
1164 if (addr.GetVersion() == 6) {
1165 net_mask = 0;
1166 // Seb: Something to do ?
1167 } else {
1168 if (transportRegistry.QueryValue("IPMask", str))
1169 net_mask = str;
1170 else {
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";
1177 else
1178 net_mask = 0;
1181 return TRUE;
1184 PEthSocket::Address macAddress;
1185 if (!QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(macAddress), macAddress.b))
1186 return FALSE;
1188 PINDEX dhcpCount;
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)) {
1193 struct DhcpInfo {
1194 DWORD index;
1195 PIPSocket::Address ipAddress;
1196 PIPSocket::Address mask;
1197 PIPSocket::Address server;
1198 PIPSocket::Address anotherAddress;
1199 DWORD unknown1;
1200 DWORD unknown2;
1201 DWORD unknown3;
1202 DWORD unknown4;
1203 DWORD unknown5;
1204 DWORD unknown6;
1205 BYTE unknown7;
1206 PEthSocket::Address macAddress;
1207 } * dhcpInfo = (DhcpInfo *)(const char *)str;
1208 if (dhcpInfo->macAddress == macAddress) {
1209 addr = dhcpInfo->ipAddress;
1210 net_mask = dhcpInfo->mask;
1211 return TRUE;
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));
1225 return TRUE;
1232 return FALSE;
1236 BOOL PWin32PacketVxD::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
1238 received = 0;
1239 if (DeviceIoControl(hDriver, IOCTL_EPACKET_READ,
1240 buf, size, buf, size, &received, &overlap)) {
1241 dwError = ERROR_SUCCESS;
1242 return TRUE;
1245 dwError = ::GetLastError();
1246 return dwError == ERROR_IO_PENDING;
1250 BOOL PWin32PacketVxD::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
1252 DWORD rxsize = 0;
1253 BYTE dummy[2];
1254 if (DeviceIoControl(hDriver, IOCTL_EPACKET_WRITE,
1255 (void *)buf, len, dummy, sizeof(dummy), &rxsize, &overlap)) {
1256 dwError = ERROR_SUCCESS;
1257 return TRUE;
1260 dwError = ::GetLastError();
1261 return dwError == ERROR_IO_PENDING;
1265 ///////////////////////////////////////////////////////////////////////////////
1267 PWin32PacketSYS::PWin32PacketSYS()
1269 #ifndef _WIN32_WCE
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)
1289 #ifndef _WIN32_WCE
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;
1294 return FALSE;
1297 if (strnicmp(name, PacketDeviceStr, sizeof(PacketDeviceStr)-1) == 0)
1298 name.Delete(0, sizeof(PacketDeviceStr)-1);
1300 #endif // !_WIN32_WCE
1301 return TRUE;
1305 BOOL PWin32PacketSYS::BindInterface(const PString & interfaceName)
1307 #ifndef _WIN32_WCE
1308 Close();
1310 if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
1311 PACKET_SERVICE_NAME "_" + interfaceName,
1312 PacketDeviceStr + interfaceName)) {
1313 dwError = ::GetLastError();
1314 return FALSE;
1317 ::SetLastError(0);
1318 hDriver = CreateFile("\\\\.\\" PACKET_SERVICE_NAME "_" + interfaceName,
1319 GENERIC_READ | GENERIC_WRITE,
1321 NULL,
1322 CREATE_ALWAYS,
1323 FILE_FLAG_OVERLAPPED,
1324 NULL);
1325 if (hDriver == INVALID_HANDLE_VALUE) {
1326 dwError = ::GetLastError();
1327 return FALSE;
1330 registryKey = SERVICES_REGISTRY_KEY + interfaceName + "\\Parameters\\Tcpip";
1331 dwError = ERROR_SUCCESS;
1333 #endif // !_WIN32_WCE
1334 return TRUE;
1338 BOOL PWin32PacketSYS::EnumIpAddress(PINDEX idx,
1339 PIPSocket::Address & addr,
1340 PIPSocket::Address & net_mask)
1342 PString str;
1343 RegistryKey registry(registryKey, RegistryKey::ReadOnly);
1345 if (!RegistryQueryMultiSz(registry, "IPAddress", idx, str)) {
1346 dwError = ERROR_NO_MORE_ITEMS;
1347 return FALSE;
1349 addr = str;
1351 if (!RegistryQueryMultiSz(registry, "SubnetMask", idx, str)) {
1352 dwError = ERROR_NO_MORE_ITEMS;
1353 return FALSE;
1355 net_mask = str;
1357 return TRUE;
1361 BOOL PWin32PacketSYS::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
1363 overlap.Reset();
1364 received = 0;
1366 if (ReadFile(hDriver, buf, size, &received, &overlap)) {
1367 dwError = ERROR_SUCCESS;
1368 return TRUE;
1371 return (dwError = ::GetLastError()) == ERROR_IO_PENDING;
1375 BOOL PWin32PacketSYS::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
1377 overlap.Reset();
1378 DWORD sent = 0;
1379 if (WriteFile(hDriver, buf, len, &sent, &overlap)) {
1380 dwError = ERROR_SUCCESS;
1381 return TRUE;
1384 dwError = ::GetLastError();
1385 return dwError == ERROR_IO_PENDING;
1388 ///////////////////////////////////////////////////////////////////////////////
1390 #ifdef _WIN32_WCE
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 )
1409 continue;
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
1419 continue;
1421 else
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
1457 else
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;
1469 else
1470 netMasks[netMasks.GetSize()] = "255.255.255.0";
1479 BOOL PWin32PacketCe::EnumInterfaces(PINDEX idx, PString & name)
1481 if( idx >= interfaces.GetSize() )
1482 return FALSE;
1484 name = interfaces[idx];
1485 return TRUE;
1489 BOOL PWin32PacketCe::BindInterface(const PString &)
1491 return TRUE;
1495 BOOL PWin32PacketCe::EnumIpAddress(PINDEX idx,
1496 PIPSocket::Address & addr,
1497 PIPSocket::Address & net_mask)
1499 if( idx >= interfaces.GetSize() )
1500 return FALSE;
1502 addr = ipAddresses[idx];
1503 net_mask = netMasks[idx];
1504 return TRUE;
1508 BOOL PWin32PacketCe::BeginRead(void *, DWORD, DWORD & , PWin32Overlapped &)
1510 return TRUE;
1514 BOOL PWin32PacketCe::BeginWrite(const void *, DWORD, PWin32Overlapped &)
1516 return TRUE;
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();
1528 PINDEX i;
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()
1540 Close();
1542 delete driver;
1546 BOOL PEthSocket::OpenSocket()
1548 PAssertAlways(PUnimplementedFunction);
1549 return FALSE;
1553 BOOL PEthSocket::Close()
1555 driver->Close();
1556 os_handle = -1;
1557 return TRUE;
1561 PString PEthSocket::GetName() const
1563 return interfaceName;
1567 BOOL PEthSocket::Connect(const PString & newName)
1569 Close();
1571 if (!driver->BindInterface(newName))
1572 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1574 interfaceName = newName;
1575 os_handle = 1;
1576 return TRUE;
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))
1589 return TRUE;
1591 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1595 BOOL PEthSocket::EnumIpAddress(PINDEX idx,
1596 PIPSocket::Address & addr,
1597 PIPSocket::Address & net_mask)
1599 if (IsOpen()) {
1600 if (driver->EnumIpAddress(idx, addr, net_mask))
1601 return TRUE;
1603 return SetErrorValues(NotFound, ENOENT);
1606 return SetErrorValues(NotOpen, EBADF);
1610 static const struct {
1611 unsigned pwlib;
1612 DWORD ndis;
1613 } FilterMasks[] = {
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)
1624 if (!IsOpen())
1625 return SetErrorValues(NotOpen, EBADF);
1627 DWORD filter = 0;
1628 if (!driver->QueryOid(OID_GEN_CURRENT_PACKET_FILTER, filter))
1629 return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1631 if (filter == 0)
1632 return PEthSocket::FilterDirected;
1634 mask = 0;
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;
1641 return TRUE;
1645 BOOL PEthSocket::SetFilter(unsigned filter, WORD type)
1647 if (!IsOpen())
1648 return SetErrorValues(NotOpen, EBADF);
1650 DWORD bits = 0;
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);
1659 filterType = type;
1660 return TRUE;
1664 PEthSocket::MediumTypes PEthSocket::GetMedium()
1666 if (!IsOpen()) {
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)
1692 if (!IsOpen())
1693 return SetErrorValues(NotOpen, EBADF, LastReadError);
1695 PINDEX idx;
1696 PINDEX numBuffers = readBuffers.GetSize();
1698 do {
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);
1708 else {
1709 if (!buffer.ReadAsync(*driver))
1710 return ConvertOSError(-1, LastReadError);
1713 if (buffer.IsCompleted() && buffer.IsType(filterType)) {
1714 lastReadCount = buffer.GetData(data, length);
1715 return TRUE;
1718 handles[idx] = buffer.GetEvent();
1721 DWORD result;
1722 PINDEX retries = 100;
1723 for (;;) {
1724 result = WaitForMultipleObjects(numBuffers, handles, FALSE, INFINITE);
1725 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + (DWORD)numBuffers)
1726 break;
1728 if (::GetLastError() != ERROR_INVALID_HANDLE || retries == 0)
1729 return ConvertOSError(-1, LastReadError);
1731 retries--;
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);
1741 return TRUE;
1745 BOOL PEthSocket::Write(const void * data, PINDEX length)
1747 if (!IsOpen())
1748 return SetErrorValues(NotOpen, EBADF, LastWriteError);
1750 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1751 PINDEX numBuffers = writeBuffers.GetSize();
1753 PINDEX idx;
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)
1786 : PBYTEArray(sz)
1788 status = Uninitialised;
1789 count = 0;
1793 PINDEX PWin32PacketBuffer::GetData(void * buf, PINDEX size)
1795 if (count > (DWORD)size)
1796 count = size;
1798 memcpy(buf, theArray, count);
1800 return count;
1804 PINDEX PWin32PacketBuffer::PutData(const void * buf, PINDEX length)
1806 count = min(GetSize(), length);
1808 memcpy(theArray, buf, count);
1810 return count;
1814 BOOL PWin32PacketBuffer::ReadAsync(PWin32PacketDriver & pkt)
1816 if (status == Progressing)
1817 return FALSE;
1819 status = Uninitialised;
1820 if (!pkt.BeginRead(theArray, GetSize(), count, overlap))
1821 return FALSE;
1823 if (pkt.GetLastError() == ERROR_SUCCESS)
1824 status = Completed;
1825 else
1826 status = Progressing;
1827 return TRUE;
1831 BOOL PWin32PacketBuffer::ReadComplete(PWin32PacketDriver & pkt)
1833 if (status != Progressing)
1834 return status == Completed;
1836 if (!pkt.CompleteIO(count, overlap)) {
1837 status = Uninitialised;
1838 return FALSE;
1841 status = Completed;
1842 return TRUE;
1846 BOOL PWin32PacketBuffer::WriteAsync(PWin32PacketDriver & pkt)
1848 if (status == Progressing)
1849 return FALSE;
1851 status = Uninitialised;
1852 if (!pkt.BeginWrite(theArray, count, overlap))
1853 return FALSE;
1855 if (pkt.GetLastError() == ERROR_SUCCESS)
1856 status = Completed;
1857 else
1858 status = Progressing;
1859 return TRUE;
1863 BOOL PWin32PacketBuffer::WriteComplete(PWin32PacketDriver & pkt)
1865 if (status != Progressing)
1866 return status == Completed;
1868 DWORD dummy;
1869 if (pkt.CompleteIO(dummy, overlap)) {
1870 status = Completed;
1871 return TRUE;
1874 status = Uninitialised;
1875 return FALSE;
1879 BOOL PWin32PacketBuffer::IsType(WORD filterType) const
1881 if (filterType == PEthSocket::TypeAll)
1882 return TRUE;
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;
1908 return 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();
1942 table.RemoveAll();
1944 PWin32AsnOid baseOid = "1.3.6.1.2.1.4.21.1";
1945 PWin32AsnOid oid = baseOid;
1947 DWORD lastVariable = 1;
1948 PWin32AsnAny value;
1949 PLongArray ifNum;
1950 PINDEX idx = 0;
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());
1957 idx = 0;
1960 switch (lastVariable) {
1961 case 1 : // network address
1963 Address addr;
1964 if (!value.GetIpAddress(addr))
1965 return FALSE; // Very confused route table
1967 table.Append(new RouteEntry(addr));
1968 break;
1971 case 2 : // device interface
1972 if (!value.GetInteger(ifNum[idx]))
1973 return FALSE;
1974 break;
1976 case 3 : // metric
1977 if (!value.GetInteger(table[idx].metric))
1978 return FALSE;
1979 break;
1981 case 7 : // Get destination (next hop)
1982 if (!value.GetIpAddress(table[idx].destination))
1983 return FALSE;
1984 break;
1986 case 11 : // Get mask
1987 if (!value.GetIpAddress(table[idx].net_mask))
1988 return FALSE;
1989 break;
1992 idx++;
1995 for (idx = 0; idx < table.GetSize(); idx++)
1996 table[idx].interfaceName = snmp.GetInterfaceName(ifNum[idx]);
1998 return TRUE;
2002 BOOL PIPSocket::GetInterfaceTable(InterfaceTable & table)
2004 PWin32SnmpLibrary & snmp = snmp.Current();
2006 PWaitAndSignal m(GetSNMPMutex());
2008 table.RemoveAll();
2011 if (!snmp.IsLoaded()) {
2012 // Error loading the SNMP library, fail safe to using whatever the
2013 // address of the local host is.
2014 Address ipAddr;
2015 if (!GetHostAddress(ipAddr))
2016 return FALSE;
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()));
2020 return TRUE;
2024 PWin32AsnOid baseOid = "1.3.6.1.2.1.4.20.1";
2025 PWin32AsnOid oid = baseOid;
2026 PWin32AsnAny value;
2027 while (snmp.GetNextOid(oid, value)) {
2028 if (!(baseOid *= oid))
2029 break;
2030 if (value.asnType != ASN_IPADDRESS)
2031 break;
2033 Address ipAddr;
2034 value.GetIpAddress(ipAddr);
2036 oid[9] = 3;
2037 Address netMask;
2038 if (!snmp.GetOid(oid, netMask))
2039 break;
2041 oid[9] = 2;
2042 AsnInteger ifIndex = -1;
2043 if (!snmp.GetOid(oid, ifIndex))
2044 break;
2046 PString macAddr;
2047 PEthSocket::Address ifPhysAddress("");
2048 PWin32AsnOid ifOid = "1.3.6.1.2.1.2.2.1.6.0";
2049 ifOid[10] = ifIndex;
2050 UINT len;
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))
2059 break;
2060 name.MakeMinimumSize();
2063 #ifdef _WIN32_WCE // Getting rid of ghost ips
2064 if ( !name.IsEmpty() )
2065 #endif
2066 table.Append(new InterfaceEntry(name, ipAddr, netMask, macAddr));
2068 oid[9] = 1;
2071 return TRUE;
2075 ///////////////////////////////////////////////////////////////////////////////