1 /* 2 * Copyright 2008 Juan Lang 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <assert.h> 20 #include <stdarg.h> 21 #include <stdlib.h> 22 #include <limits.h> 23 24 #define NONAMELESSUNION 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "snmp.h" 29 #include "iphlpapi.h" 30 #include "wine/debug.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1); 33 34 /** 35 * Utility functions 36 */ 37 static DWORD copyInt(AsnAny *value, void *src) 38 { 39 value->asnType = ASN_INTEGER; 40 value->asnValue.number = *(DWORD *)src; 41 return SNMP_ERRORSTATUS_NOERROR; 42 } 43 44 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str) 45 { 46 AsnAny strValue; 47 48 strValue.asnType = type; 49 strValue.asnValue.string.stream = str; 50 strValue.asnValue.string.length = len; 51 strValue.asnValue.string.dynamic = FALSE; 52 SnmpUtilAsnAnyCpy(value, &strValue); 53 } 54 55 typedef DWORD (*copyValueFunc)(AsnAny *value, void *src); 56 57 struct structToAsnValue 58 { 59 size_t offset; 60 copyValueFunc copy; 61 }; 62 63 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map, 64 UINT mapLen, void *record, UINT id, SnmpVarBind *pVarBind) 65 { 66 /* OIDs are 1-based */ 67 if (!id) 68 return SNMP_ERRORSTATUS_NOSUCHNAME; 69 --id; 70 if (id >= mapLen) 71 return SNMP_ERRORSTATUS_NOSUCHNAME; 72 if (!map[id].copy) 73 return SNMP_ERRORSTATUS_NOSUCHNAME; 74 return map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset); 75 } 76 77 static DWORD copyIpAddr(AsnAny *value, void *src) 78 { 79 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src); 80 return SNMP_ERRORSTATUS_NOERROR; 81 } 82 83 static UINT mib2[] = { 1,3,6,1,2,1 }; 84 static UINT mib2System[] = { 1,3,6,1,2,1,1 }; 85 86 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind, 87 AsnInteger32 *pErrorStatus); 88 89 struct mibImplementation 90 { 91 AsnObjectIdentifier name; 92 void (*init)(void); 93 varqueryfunc query; 94 void (*cleanup)(void); 95 }; 96 97 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 }; 98 static PMIB_IFTABLE ifTable; 99 100 static void mib2IfNumberInit(void) 101 { 102 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE); 103 104 if (ret == ERROR_INSUFFICIENT_BUFFER) 105 { 106 MIB_IFTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); 107 if (table) 108 { 109 if (!GetIfTable(table, &size, FALSE)) ifTable = table; 110 else HeapFree(GetProcessHeap(), 0, table ); 111 } 112 } 113 } 114 115 static void mib2IfNumberCleanup(void) 116 { 117 HeapFree(GetProcessHeap(), 0, ifTable); 118 } 119 120 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind, 121 AsnInteger32 *pErrorStatus) 122 { 123 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber); 124 BOOL ret = TRUE; 125 126 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 127 pErrorStatus); 128 129 switch (bPduType) 130 { 131 case SNMP_PDU_GET: 132 case SNMP_PDU_GETNEXT: 133 if ((bPduType == SNMP_PDU_GET && 134 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)) 135 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength) 136 < 0) 137 { 138 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0; 139 140 copyInt(&pVarBind->value, &numIfs); 141 if (bPduType == SNMP_PDU_GETNEXT) 142 { 143 SnmpUtilOidFree(&pVarBind->name); 144 SnmpUtilOidCpy(&pVarBind->name, &numberOid); 145 } 146 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR; 147 } 148 else 149 { 150 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 151 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't 152 * need to set it here. 153 */ 154 } 155 break; 156 case SNMP_PDU_SET: 157 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 158 ret = FALSE; 159 break; 160 default: 161 FIXME("0x%02x: unsupported PDU type\n", bPduType); 162 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 163 } 164 return ret; 165 } 166 167 static DWORD copyOperStatus(AsnAny *value, void *src) 168 { 169 value->asnType = ASN_INTEGER; 170 /* The IPHlpApi definition of operational status differs from the MIB2 one, 171 * so map it to the MIB2 value. 172 */ 173 switch (*(DWORD *)src) 174 { 175 case MIB_IF_OPER_STATUS_OPERATIONAL: 176 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP; 177 break; 178 case MIB_IF_OPER_STATUS_CONNECTING: 179 case MIB_IF_OPER_STATUS_CONNECTED: 180 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING; 181 break; 182 default: 183 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN; 184 }; 185 return SNMP_ERRORSTATUS_NOERROR; 186 } 187 188 /* Given an OID and a base OID that it must begin with, finds the item and 189 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID 190 * foo, returns item 1 and instance 2. 191 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is 192 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME. 193 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and 194 * instance, or item 1, instance 1 if either is missing. 195 */ 196 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid, 197 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance) 198 { 199 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; 200 201 switch (bPduType) 202 { 203 case SNMP_PDU_GETNEXT: 204 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) 205 { 206 *item = 1; 207 *instance = 1; 208 } 209 else if (!SnmpUtilOidNCmp(oid, base, base->idLength)) 210 { 211 if (oid->idLength == base->idLength || 212 oid->idLength == base->idLength + 1) 213 { 214 /* Either the table or an item within the table is specified, 215 * but the instance is not. Get the first instance. 216 */ 217 *instance = 1; 218 if (oid->idLength == base->idLength + 1) 219 *item = oid->ids[base->idLength]; 220 else 221 *item = 1; 222 } 223 else 224 { 225 *item = oid->ids[base->idLength]; 226 *instance = oid->ids[base->idLength + 1] + 1; 227 } 228 } 229 else 230 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 231 break; 232 default: 233 if (!SnmpUtilOidNCmp(oid, base, base->idLength)) 234 { 235 if (oid->idLength == base->idLength || 236 oid->idLength == base->idLength + 1) 237 { 238 /* Either the table or an item within the table is specified, 239 * but the instance is not. 240 */ 241 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 242 } 243 else 244 { 245 *item = oid->ids[base->idLength]; 246 *instance = oid->ids[base->idLength + 1]; 247 } 248 } 249 else 250 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 251 } 252 return ret; 253 } 254 255 /* Given an OID and a base OID that it must begin with, finds the item from the 256 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1. 257 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns 258 * SNMP_ERRORSTATUS_NOSUCHNAME. 259 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item 260 * 1 if the item is missing. 261 */ 262 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid, 263 AsnObjectIdentifier *base, BYTE bPduType, UINT *item) 264 { 265 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; 266 267 switch (bPduType) 268 { 269 case SNMP_PDU_GETNEXT: 270 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) 271 *item = 1; 272 else if (!SnmpUtilOidNCmp(oid, base, base->idLength)) 273 { 274 if (oid->idLength == base->idLength) 275 { 276 /* The item is missing, assume the first item */ 277 *item = 1; 278 } 279 else 280 *item = oid->ids[base->idLength] + 1; 281 } 282 else 283 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 284 break; 285 default: 286 if (!SnmpUtilOidNCmp(oid, base, base->idLength)) 287 { 288 if (oid->idLength == base->idLength) 289 { 290 /* The item is missing */ 291 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 292 } 293 else 294 { 295 *item = oid->ids[base->idLength]; 296 if (!*item) 297 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 298 } 299 } 300 else 301 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 302 } 303 return ret; 304 } 305 306 struct GenericTable 307 { 308 DWORD numEntries; 309 BYTE entries[1]; 310 }; 311 312 static DWORD oidToIpAddr(AsnObjectIdentifier *oid) 313 { 314 assert(oid && oid->idLength >= 4); 315 /* Map the IDs to an IP address in little-endian order */ 316 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 | 317 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0]; 318 } 319 320 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst); 321 typedef int (__cdecl *compareFunc)(const void *key, const void *value); 322 323 /* Finds the first value in the table that matches key. Returns its 1-based 324 * index if found, or 0 if not found. 325 */ 326 static UINT findValueInTable(const void *key, 327 struct GenericTable *table, size_t tableEntrySize, compareFunc compare) 328 { 329 UINT index = 0; 330 void *value; 331 332 value = bsearch(key, table->entries, table->numEntries, tableEntrySize, 333 compare); 334 if (value) 335 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize + 1; 336 return index; 337 } 338 339 /* Finds the first value in the table that matches oid, using makeKey to 340 * convert the oid to a key for comparison. Returns the value's 1-based 341 * index if found, or 0 if not found. 342 */ 343 static UINT findOidInTable(AsnObjectIdentifier *oid, 344 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, 345 compareFunc compare) 346 { 347 UINT index = 0; 348 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize); 349 350 if (key) 351 { 352 makeKey(oid, key); 353 index = findValueInTable(key, table, tableEntrySize, compare); 354 HeapFree(GetProcessHeap(), 0, key); 355 } 356 return index; 357 } 358 359 /* Finds the first successor to the value in the table that does matches oid, 360 * using makeKey to convert the oid to a key for comparison. A successor is 361 * a value that does not match oid, so if multiple entries match an oid, only 362 * the first will ever be returned using this method. 363 * Returns the successor's 1-based index if found, or 0 if not found. 364 */ 365 static UINT findNextOidInTable(AsnObjectIdentifier *oid, 366 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, 367 compareFunc compare) 368 { 369 UINT index = 0; 370 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize); 371 372 if (key) 373 { 374 makeKey(oid, key); 375 index = findValueInTable(key, table, tableEntrySize, compare); 376 if (index == 0) 377 { 378 /* Not found in table. If it's less than the first entry, return 379 * the first index. Otherwise just return 0 and let the caller 380 * handle finding the successor. 381 */ 382 if (compare(key, table->entries) < 0) 383 index = 1; 384 } 385 else 386 { 387 /* Skip any entries that match the same key. This enumeration will 388 * be incomplete, but it's what Windows appears to do if there are 389 * multiple entries with the same index in a table, and it avoids 390 * an infinite loop. 391 */ 392 for (++index; index <= table->numEntries && compare(key, 393 &table->entries[tableEntrySize * (index - 1)]) == 0; ++index) 394 ; 395 } 396 HeapFree(GetProcessHeap(), 0, key); 397 } 398 return index; 399 } 400 401 /* Given an OID and a base OID that it must begin with, finds the item and 402 * element of the table whose value matches the instance from the OID. 403 * The OID is converted to a key with the function makeKey, and compared 404 * against entries in the table with the function compare. 405 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is 406 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME. 407 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and 408 * instance, or item 1, instance 1 if either is missing. 409 */ 410 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid, 411 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType, 412 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, 413 compareFunc compare, UINT *item, UINT *instance) 414 { 415 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; 416 417 if (!table) 418 return SNMP_ERRORSTATUS_NOSUCHNAME; 419 420 switch (bPduType) 421 { 422 case SNMP_PDU_GETNEXT: 423 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) 424 { 425 /* Return the first item and instance from the table */ 426 *item = 1; 427 *instance = 1; 428 } 429 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) && 430 oid->idLength < base->idLength + instanceLen + 1) 431 { 432 /* Either the table or an item is specified, but the instance is 433 * not. 434 */ 435 *instance = 1; 436 if (oid->idLength >= base->idLength + 1) 437 { 438 *item = oid->ids[base->idLength]; 439 if (!*item) 440 *item = 1; 441 } 442 else 443 *item = 1; 444 } 445 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) && 446 oid->idLength == base->idLength + instanceLen + 1) 447 { 448 *item = oid->ids[base->idLength]; 449 if (!*item) 450 { 451 *instance = 1; 452 *item = 1; 453 } 454 else 455 { 456 AsnObjectIdentifier instanceOid = { instanceLen, 457 oid->ids + base->idLength + 1 }; 458 459 *instance = findNextOidInTable(&instanceOid, table, 460 tableEntrySize, makeKey, compare); 461 if (!*instance || *instance > table->numEntries) 462 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 463 } 464 } 465 else 466 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 467 break; 468 default: 469 if (!SnmpUtilOidNCmp(oid, base, base->idLength) && 470 oid->idLength == base->idLength + instanceLen + 1) 471 { 472 *item = oid->ids[base->idLength]; 473 if (!*item) 474 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 475 else 476 { 477 AsnObjectIdentifier instanceOid = { instanceLen, 478 oid->ids + base->idLength + 1 }; 479 480 *instance = findOidInTable(&instanceOid, table, tableEntrySize, 481 makeKey, compare); 482 if (!*instance) 483 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 484 } 485 } 486 else 487 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 488 } 489 return ret; 490 } 491 492 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base, 493 UINT item) 494 { 495 UINT id; 496 AsnObjectIdentifier oid; 497 INT ret; 498 499 SnmpUtilOidFree(dst); 500 ret = SnmpUtilOidCpy(dst, base); 501 if (ret) 502 { 503 oid.idLength = 1; 504 oid.ids = &id; 505 id = item; 506 ret = SnmpUtilOidAppend(dst, &oid); 507 } 508 return ret; 509 } 510 511 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst, 512 AsnObjectIdentifier *base, UINT item, DWORD addr) 513 { 514 UINT id; 515 BYTE *ptr; 516 AsnObjectIdentifier oid; 517 INT ret; 518 519 ret = setOidWithItem(dst, base, item); 520 if (ret) 521 { 522 oid.idLength = 1; 523 oid.ids = &id; 524 for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD); 525 ptr++) 526 { 527 id = *ptr; 528 ret = SnmpUtilOidAppend(dst, &oid); 529 } 530 } 531 return ret; 532 } 533 534 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst, 535 AsnObjectIdentifier *base, UINT item, UINT instance) 536 { 537 AsnObjectIdentifier oid; 538 INT ret; 539 540 ret = setOidWithItem(dst, base, item); 541 if (ret) 542 { 543 oid.idLength = 1; 544 oid.ids = &instance; 545 ret = SnmpUtilOidAppend(dst, &oid); 546 } 547 return ret; 548 } 549 550 static DWORD copyIfRowDescr(AsnAny *value, void *src) 551 { 552 PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src - 553 FIELD_OFFSET(MIB_IFROW, dwDescrLen)); 554 DWORD ret; 555 556 if (row->dwDescrLen) 557 { 558 setStringValue(value, ASN_OCTETSTRING, row->dwDescrLen, row->bDescr); 559 ret = SNMP_ERRORSTATUS_NOERROR; 560 } 561 else 562 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 563 return ret; 564 } 565 566 static DWORD copyIfRowPhysAddr(AsnAny *value, void *src) 567 { 568 PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src - 569 FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen)); 570 DWORD ret; 571 572 if (row->dwPhysAddrLen) 573 { 574 setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen, 575 row->bPhysAddr); 576 ret = SNMP_ERRORSTATUS_NOERROR; 577 } 578 else 579 ret = SNMP_ERRORSTATUS_NOSUCHNAME; 580 return ret; 581 } 582 583 static struct structToAsnValue mib2IfEntryMap[] = { 584 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt }, 585 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyIfRowDescr }, 586 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt }, 587 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt }, 588 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt }, 589 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyIfRowPhysAddr }, 590 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt }, 591 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus }, 592 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt }, 593 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt }, 594 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt }, 595 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt }, 596 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt }, 597 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt }, 598 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt }, 599 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt }, 600 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt }, 601 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt }, 602 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt }, 603 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt }, 604 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt }, 605 }; 606 607 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 }; 608 609 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind, 610 AsnInteger32 *pErrorStatus) 611 { 612 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry); 613 BOOL ret = TRUE; 614 615 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 616 pErrorStatus); 617 618 switch (bPduType) 619 { 620 case SNMP_PDU_GET: 621 case SNMP_PDU_GETNEXT: 622 if (!ifTable) 623 { 624 /* There is no interface present, so let the caller deal 625 * with finding the successor. 626 */ 627 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 628 } 629 else 630 { 631 UINT tableIndex = 0, item = 0; 632 633 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name, 634 &entryOid, bPduType, &item, &tableIndex); 635 if (!*pErrorStatus) 636 { 637 assert(tableIndex); 638 assert(item); 639 if (tableIndex > ifTable->dwNumEntries) 640 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 641 else 642 { 643 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap, 644 DEFINE_SIZEOF(mib2IfEntryMap), 645 &ifTable->table[tableIndex - 1], item, 646 pVarBind); 647 if (bPduType == SNMP_PDU_GETNEXT) 648 ret = setOidWithItemAndInteger(&pVarBind->name, 649 &entryOid, item, tableIndex); 650 } 651 } 652 } 653 break; 654 case SNMP_PDU_SET: 655 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 656 ret = FALSE; 657 break; 658 default: 659 FIXME("0x%02x: unsupported PDU type\n", bPduType); 660 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 661 } 662 return ret; 663 } 664 665 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 }; 666 static MIB_IPSTATS ipStats; 667 668 static void mib2IpStatsInit(void) 669 { 670 GetIpStatistics(&ipStats); 671 } 672 673 static struct structToAsnValue mib2IpMap[] = { 674 { FIELD_OFFSET(MIB_IPSTATS, u.dwForwarding), copyInt }, /* 1 */ 675 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */ 676 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */ 677 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */ 678 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */ 679 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */ 680 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */ 681 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */ 682 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */ 683 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */ 684 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */ 685 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */ 686 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */ 687 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */ 688 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */ 689 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */ 690 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */ 691 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */ 692 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */ 693 { 0, NULL }, /* 20: not used, IP addr table */ 694 { 0, NULL }, /* 21: not used, route table */ 695 { 0, NULL }, /* 22: not used, net to media (ARP) table */ 696 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */ 697 }; 698 699 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind, 700 AsnInteger32 *pErrorStatus) 701 { 702 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip); 703 UINT item = 0; 704 BOOL ret = TRUE; 705 706 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 707 pErrorStatus); 708 709 switch (bPduType) 710 { 711 case SNMP_PDU_GET: 712 case SNMP_PDU_GETNEXT: 713 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType, 714 &item); 715 if (!*pErrorStatus) 716 { 717 *pErrorStatus = mapStructEntryToValue(mib2IpMap, 718 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, pVarBind); 719 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 720 ret = setOidWithItem(&pVarBind->name, &myOid, item); 721 } 722 break; 723 case SNMP_PDU_SET: 724 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 725 ret = FALSE; 726 break; 727 default: 728 FIXME("0x%02x: unsupported PDU type\n", bPduType); 729 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 730 } 731 return ret; 732 } 733 734 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 }; 735 static PMIB_IPADDRTABLE ipAddrTable; 736 737 static struct structToAsnValue mib2IpAddrMap[] = { 738 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr }, 739 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt }, 740 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr }, 741 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt }, 742 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt }, 743 }; 744 745 static void mib2IpAddrInit(void) 746 { 747 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE); 748 749 if (ret == ERROR_INSUFFICIENT_BUFFER) 750 { 751 MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); 752 if (table) 753 { 754 if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table; 755 else HeapFree(GetProcessHeap(), 0, table ); 756 } 757 } 758 } 759 760 static void mib2IpAddrCleanup(void) 761 { 762 HeapFree(GetProcessHeap(), 0, ipAddrTable); 763 } 764 765 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst) 766 { 767 MIB_IPADDRROW *row = dst; 768 769 row->dwAddr = oidToIpAddr(oid); 770 } 771 772 static int __cdecl compareIpAddrRow(const void *a, const void *b) 773 { 774 const MIB_IPADDRROW *key = a, *value = b; 775 776 return key->dwAddr - value->dwAddr; 777 } 778 779 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind, 780 AsnInteger32 *pErrorStatus) 781 { 782 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr); 783 UINT tableIndex = 0, item = 0; 784 BOOL ret = TRUE; 785 786 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 787 pErrorStatus); 788 789 switch (bPduType) 790 { 791 case SNMP_PDU_GET: 792 case SNMP_PDU_GETNEXT: 793 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, 794 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable, 795 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item, 796 &tableIndex); 797 if (!*pErrorStatus) 798 { 799 assert(tableIndex); 800 assert(item); 801 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap, 802 DEFINE_SIZEOF(mib2IpAddrMap), 803 &ipAddrTable->table[tableIndex - 1], item, pVarBind); 804 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 805 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, 806 ipAddrTable->table[tableIndex - 1].dwAddr); 807 } 808 break; 809 case SNMP_PDU_SET: 810 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 811 ret = FALSE; 812 break; 813 default: 814 FIXME("0x%02x: unsupported PDU type\n", bPduType); 815 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 816 } 817 return ret; 818 } 819 820 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 }; 821 static PMIB_IPFORWARDTABLE ipRouteTable; 822 823 static struct structToAsnValue mib2IpRouteMap[] = { 824 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr }, 825 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt }, 826 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt }, 827 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt }, 828 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt }, 829 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt }, 830 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr }, 831 { FIELD_OFFSET(MIB_IPFORWARDROW, u1.dwForwardType), copyInt }, 832 { FIELD_OFFSET(MIB_IPFORWARDROW, u2.dwForwardProto), copyInt }, 833 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt }, 834 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr }, 835 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt }, 836 }; 837 838 static void mib2IpRouteInit(void) 839 { 840 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE); 841 842 if (ret == ERROR_INSUFFICIENT_BUFFER) 843 { 844 MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); 845 if (table) 846 { 847 if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table; 848 else HeapFree(GetProcessHeap(), 0, table ); 849 } 850 } 851 } 852 853 static void mib2IpRouteCleanup(void) 854 { 855 HeapFree(GetProcessHeap(), 0, ipRouteTable); 856 } 857 858 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst) 859 { 860 MIB_IPFORWARDROW *row = dst; 861 862 row->dwForwardDest = oidToIpAddr(oid); 863 } 864 865 static int __cdecl compareIpForwardRow(const void *a, const void *b) 866 { 867 const MIB_IPFORWARDROW *key = a, *value = b; 868 869 return key->dwForwardDest - value->dwForwardDest; 870 } 871 872 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind, 873 AsnInteger32 *pErrorStatus) 874 { 875 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute); 876 UINT tableIndex = 0, item = 0; 877 BOOL ret = TRUE; 878 879 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 880 pErrorStatus); 881 882 switch (bPduType) 883 { 884 case SNMP_PDU_GET: 885 case SNMP_PDU_GETNEXT: 886 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, 887 &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable, 888 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow, 889 &item, &tableIndex); 890 if (!*pErrorStatus) 891 { 892 assert(tableIndex); 893 assert(item); 894 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap, 895 DEFINE_SIZEOF(mib2IpRouteMap), 896 &ipRouteTable->table[tableIndex - 1], item, pVarBind); 897 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 898 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, 899 ipRouteTable->table[tableIndex - 1].dwForwardDest); 900 } 901 break; 902 case SNMP_PDU_SET: 903 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 904 ret = FALSE; 905 break; 906 default: 907 FIXME("0x%02x: unsupported PDU type\n", bPduType); 908 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 909 } 910 return ret; 911 } 912 913 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 }; 914 static PMIB_IPNETTABLE ipNetTable; 915 916 static DWORD copyIpNetPhysAddr(AsnAny *value, void *src) 917 { 918 PMIB_IPNETROW row = (PMIB_IPNETROW)((BYTE *)src - FIELD_OFFSET(MIB_IPNETROW, 919 dwPhysAddrLen)); 920 921 setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen, row->bPhysAddr); 922 return SNMP_ERRORSTATUS_NOERROR; 923 } 924 925 static struct structToAsnValue mib2IpNetMap[] = { 926 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt }, 927 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyIpNetPhysAddr }, 928 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr }, 929 { FIELD_OFFSET(MIB_IPNETROW, u.dwType), copyInt }, 930 }; 931 932 static void mib2IpNetInit(void) 933 { 934 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE); 935 936 if (ret == ERROR_INSUFFICIENT_BUFFER) 937 { 938 MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); 939 if (table) 940 { 941 if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table; 942 else HeapFree(GetProcessHeap(), 0, table ); 943 } 944 } 945 } 946 947 static void mib2IpNetCleanup(void) 948 { 949 HeapFree(GetProcessHeap(), 0, ipNetTable); 950 } 951 952 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind, 953 AsnInteger32 *pErrorStatus) 954 { 955 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet); 956 BOOL ret = TRUE; 957 958 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 959 pErrorStatus); 960 961 switch (bPduType) 962 { 963 case SNMP_PDU_GET: 964 case SNMP_PDU_GETNEXT: 965 if (!ipNetTable) 966 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 967 else 968 { 969 UINT tableIndex = 0, item = 0; 970 971 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name, 972 &myOid, bPduType, &item, &tableIndex); 973 if (!*pErrorStatus) 974 { 975 assert(tableIndex); 976 assert(item); 977 if (tableIndex > ipNetTable->dwNumEntries) 978 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 979 else 980 { 981 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap, 982 DEFINE_SIZEOF(mib2IpNetMap), 983 &ipNetTable[tableIndex - 1], item, pVarBind); 984 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 985 ret = setOidWithItemAndInteger(&pVarBind->name, &myOid, 986 item, tableIndex); 987 } 988 } 989 } 990 break; 991 case SNMP_PDU_SET: 992 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 993 ret = FALSE; 994 break; 995 default: 996 FIXME("0x%02x: unsupported PDU type\n", bPduType); 997 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 998 } 999 return ret; 1000 } 1001 1002 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 }; 1003 static MIB_ICMP icmpStats; 1004 1005 static void mib2IcmpInit(void) 1006 { 1007 GetIcmpStatistics(&icmpStats); 1008 } 1009 1010 static struct structToAsnValue mib2IcmpMap[] = { 1011 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt }, 1012 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt }, 1013 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt }, 1014 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt }, 1015 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt }, 1016 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt }, 1017 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt }, 1018 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt }, 1019 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt }, 1020 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt }, 1021 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt }, 1022 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt }, 1023 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt }, 1024 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt }, 1025 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt }, 1026 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt }, 1027 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt }, 1028 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt }, 1029 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt }, 1030 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt }, 1031 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt }, 1032 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt }, 1033 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt }, 1034 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt }, 1035 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt }, 1036 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt }, 1037 }; 1038 1039 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind, 1040 AsnInteger32 *pErrorStatus) 1041 { 1042 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp); 1043 UINT item = 0; 1044 BOOL ret = TRUE; 1045 1046 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 1047 pErrorStatus); 1048 1049 switch (bPduType) 1050 { 1051 case SNMP_PDU_GET: 1052 case SNMP_PDU_GETNEXT: 1053 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType, 1054 &item); 1055 if (!*pErrorStatus) 1056 { 1057 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap, 1058 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, 1059 pVarBind); 1060 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 1061 ret = setOidWithItem(&pVarBind->name, &myOid, item); 1062 } 1063 break; 1064 case SNMP_PDU_SET: 1065 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 1066 ret = FALSE; 1067 break; 1068 default: 1069 FIXME("0x%02x: unsupported PDU type\n", bPduType); 1070 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 1071 } 1072 return ret; 1073 } 1074 1075 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 }; 1076 static MIB_TCPSTATS tcpStats; 1077 1078 static void mib2TcpInit(void) 1079 { 1080 GetTcpStatistics(&tcpStats); 1081 } 1082 1083 static struct structToAsnValue mib2TcpMap[] = { 1084 { FIELD_OFFSET(MIB_TCPSTATS, u.dwRtoAlgorithm), copyInt }, 1085 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt }, 1086 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt }, 1087 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt }, 1088 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt }, 1089 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt }, 1090 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt }, 1091 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt }, 1092 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt }, 1093 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt }, 1094 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt }, 1095 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt }, 1096 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt }, 1097 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt }, 1098 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt }, 1099 }; 1100 1101 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind, 1102 AsnInteger32 *pErrorStatus) 1103 { 1104 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp); 1105 UINT item = 0; 1106 BOOL ret = TRUE; 1107 1108 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 1109 pErrorStatus); 1110 1111 switch (bPduType) 1112 { 1113 case SNMP_PDU_GET: 1114 case SNMP_PDU_GETNEXT: 1115 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType, 1116 &item); 1117 if (!*pErrorStatus) 1118 { 1119 *pErrorStatus = mapStructEntryToValue(mib2TcpMap, 1120 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, pVarBind); 1121 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 1122 ret = setOidWithItem(&pVarBind->name, &myOid, item); 1123 } 1124 break; 1125 case SNMP_PDU_SET: 1126 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 1127 ret = FALSE; 1128 break; 1129 default: 1130 FIXME("0x%02x: unsupported PDU type\n", bPduType); 1131 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 1132 } 1133 return ret; 1134 } 1135 1136 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 }; 1137 static MIB_UDPSTATS udpStats; 1138 1139 static void mib2UdpInit(void) 1140 { 1141 GetUdpStatistics(&udpStats); 1142 } 1143 1144 static struct structToAsnValue mib2UdpMap[] = { 1145 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt }, 1146 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt }, 1147 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt }, 1148 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt }, 1149 }; 1150 1151 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind, 1152 AsnInteger32 *pErrorStatus) 1153 { 1154 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp); 1155 UINT item; 1156 BOOL ret = TRUE; 1157 1158 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 1159 pErrorStatus); 1160 1161 switch (bPduType) 1162 { 1163 case SNMP_PDU_GET: 1164 case SNMP_PDU_GETNEXT: 1165 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType, 1166 &item); 1167 if (!*pErrorStatus) 1168 { 1169 *pErrorStatus = mapStructEntryToValue(mib2UdpMap, 1170 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, pVarBind); 1171 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 1172 ret = setOidWithItem(&pVarBind->name, &myOid, item); 1173 } 1174 break; 1175 case SNMP_PDU_SET: 1176 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 1177 ret = FALSE; 1178 break; 1179 default: 1180 FIXME("0x%02x: unsupported PDU type\n", bPduType); 1181 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 1182 } 1183 return ret; 1184 } 1185 1186 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 }; 1187 static PMIB_UDPTABLE udpTable; 1188 1189 static void mib2UdpEntryInit(void) 1190 { 1191 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE); 1192 1193 if (ret == ERROR_INSUFFICIENT_BUFFER) 1194 { 1195 MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); 1196 if (table) 1197 { 1198 if (!GetUdpTable(table, &size, TRUE)) udpTable = table; 1199 else HeapFree(GetProcessHeap(), 0, table); 1200 } 1201 } 1202 } 1203 1204 static void mib2UdpEntryCleanup(void) 1205 { 1206 HeapFree(GetProcessHeap(), 0, udpTable); 1207 } 1208 1209 static struct structToAsnValue mib2UdpEntryMap[] = { 1210 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr }, 1211 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt }, 1212 }; 1213 1214 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst) 1215 { 1216 MIB_UDPROW *row = dst; 1217 1218 assert(oid && oid->idLength >= 5); 1219 row->dwLocalAddr = oidToIpAddr(oid); 1220 row->dwLocalPort = oid->ids[4]; 1221 } 1222 1223 static int __cdecl compareUdpRow(const void *a, const void *b) 1224 { 1225 const MIB_UDPROW *key = a, *value = b; 1226 int ret; 1227 1228 ret = key->dwLocalAddr - value->dwLocalAddr; 1229 if (ret == 0) 1230 ret = key->dwLocalPort - value->dwLocalPort; 1231 return ret; 1232 } 1233 1234 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind, 1235 AsnInteger32 *pErrorStatus) 1236 { 1237 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry); 1238 BOOL ret = TRUE; 1239 1240 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), 1241 pErrorStatus); 1242 1243 switch (bPduType) 1244 { 1245 case SNMP_PDU_GET: 1246 case SNMP_PDU_GETNEXT: 1247 if (!udpTable) 1248 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 1249 else 1250 { 1251 UINT tableIndex = 0, item = 0; 1252 1253 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid, 1254 5, bPduType, (struct GenericTable *)udpTable, 1255 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item, 1256 &tableIndex); 1257 if (!*pErrorStatus) 1258 { 1259 assert(tableIndex); 1260 assert(item); 1261 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap, 1262 DEFINE_SIZEOF(mib2UdpEntryMap), 1263 &udpTable->table[tableIndex - 1], item, pVarBind); 1264 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) 1265 { 1266 AsnObjectIdentifier oid; 1267 1268 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, 1269 udpTable->table[tableIndex - 1].dwLocalAddr); 1270 if (ret) 1271 { 1272 oid.idLength = 1; 1273 oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort; 1274 ret = SnmpUtilOidAppend(&pVarBind->name, &oid); 1275 } 1276 } 1277 } 1278 } 1279 break; 1280 case SNMP_PDU_SET: 1281 *pErrorStatus = SNMP_ERRORSTATUS_READONLY; 1282 ret = FALSE; 1283 break; 1284 default: 1285 FIXME("0x%02x: unsupported PDU type\n", bPduType); 1286 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; 1287 } 1288 return ret; 1289 } 1290 1291 /* This list MUST BE lexicographically sorted */ 1292 static struct mibImplementation supportedIDs[] = { 1293 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery, 1294 mib2IfNumberCleanup }, 1295 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL }, 1296 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL }, 1297 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery, 1298 mib2IpAddrCleanup }, 1299 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery, 1300 mib2IpRouteCleanup }, 1301 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup }, 1302 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL }, 1303 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL }, 1304 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL }, 1305 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery, 1306 mib2UdpEntryCleanup }, 1307 }; 1308 static UINT minSupportedIDLength; 1309 1310 /***************************************************************************** 1311 * SnmpExtensionInit [INETMIB1.@] 1312 */ 1313 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference, 1314 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion) 1315 { 1316 AsnObjectIdentifier myOid = DEFINE_OID(mib2System); 1317 UINT i; 1318 1319 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent, 1320 pFirstSupportedRegion); 1321 1322 minSupportedIDLength = UINT_MAX; 1323 for (i = 0; i < ARRAY_SIZE(supportedIDs); i++) 1324 { 1325 if (supportedIDs[i].init) 1326 supportedIDs[i].init(); 1327 if (supportedIDs[i].name.idLength < minSupportedIDLength) 1328 minSupportedIDLength = supportedIDs[i].name.idLength; 1329 } 1330 *phSubagentTrapEvent = NULL; 1331 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid); 1332 return TRUE; 1333 } 1334 1335 static void cleanup(void) 1336 { 1337 UINT i; 1338 1339 for (i = 0; i < ARRAY_SIZE(supportedIDs); i++) 1340 if (supportedIDs[i].cleanup) 1341 supportedIDs[i].cleanup(); 1342 } 1343 1344 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength, 1345 UINT *matchingIndex) 1346 { 1347 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0; 1348 AsnObjectIdentifier oid1 = { idLength, ids}; 1349 1350 if (!idLength) 1351 return NULL; 1352 1353 while (indexLow <= indexHigh) 1354 { 1355 INT cmp, i = (indexLow + indexHigh) / 2; 1356 if (!(cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength))) 1357 { 1358 *matchingIndex = i; 1359 return &supportedIDs[i]; 1360 } 1361 if (cmp > 0) 1362 indexLow = i + 1; 1363 else 1364 indexHigh = i - 1; 1365 } 1366 return NULL; 1367 } 1368 1369 /***************************************************************************** 1370 * SnmpExtensionQuery [INETMIB1.@] 1371 */ 1372 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList, 1373 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex) 1374 { 1375 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2); 1376 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0; 1377 UINT i; 1378 BOOL ret = TRUE; 1379 1380 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList, 1381 pErrorStatus, pErrorIndex); 1382 1383 for (i = 0; !error && i < pVarBindList->len; i++) 1384 { 1385 /* Ignore any OIDs not in MIB2 */ 1386 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid, 1387 mib2oid.idLength)) 1388 { 1389 struct mibImplementation *impl = NULL; 1390 UINT len, matchingIndex = 0; 1391 1392 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name)); 1393 /* Search for an implementation matching as many octets as possible 1394 */ 1395 for (len = pVarBindList->list[i].name.idLength; 1396 len >= minSupportedIDLength && !impl; len--) 1397 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len, 1398 &matchingIndex); 1399 if (impl && impl->query) 1400 ret = impl->query(bPduType, &pVarBindList->list[i], &error); 1401 else 1402 error = SNMP_ERRORSTATUS_NOSUCHNAME; 1403 if (error == SNMP_ERRORSTATUS_NOSUCHNAME && 1404 bPduType == SNMP_PDU_GETNEXT) 1405 { 1406 /* GetNext is special: it finds the successor to the given OID, 1407 * so we have to continue until an implementation handles the 1408 * query or we exhaust the table of supported OIDs. 1409 */ 1410 for (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME && 1411 matchingIndex < DEFINE_SIZEOF(supportedIDs); 1412 matchingIndex++) 1413 { 1414 error = SNMP_ERRORSTATUS_NOERROR; 1415 impl = &supportedIDs[matchingIndex]; 1416 if (impl->query) 1417 ret = impl->query(bPduType, &pVarBindList->list[i], 1418 &error); 1419 else 1420 error = SNMP_ERRORSTATUS_NOSUCHNAME; 1421 } 1422 /* If the query still isn't resolved, set the OID to the 1423 * successor to the last entry in the table. 1424 */ 1425 if (error == SNMP_ERRORSTATUS_NOSUCHNAME) 1426 { 1427 SnmpUtilOidFree(&pVarBindList->list[i].name); 1428 ret = SnmpUtilOidCpy(&pVarBindList->list[i].name, 1429 &supportedIDs[matchingIndex - 1].name); 1430 pVarBindList->list[i].name.ids[ 1431 pVarBindList->list[i].name.idLength - 1] += 1; 1432 } 1433 } 1434 if (error) 1435 errorIndex = i + 1; 1436 } 1437 } 1438 *pErrorStatus = error; 1439 *pErrorIndex = errorIndex; 1440 return ret; 1441 } 1442 1443 /***************************************************************************** 1444 * DllMain [INETMIB1.@] 1445 */ 1446 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 1447 { 1448 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); 1449 1450 switch (fdwReason) 1451 { 1452 case DLL_PROCESS_ATTACH: 1453 DisableThreadLibraryCalls(hinstDLL); 1454 break; 1455 case DLL_PROCESS_DETACH: 1456 if (lpvReserved) break; 1457 cleanup(); 1458 break; 1459 } 1460 1461 return TRUE; 1462 } 1463