Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_iph/kernel_iph_net.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013 Martin Willi
! 3: * Copyright (C) 2013 revosec AG
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: /* Windows 7, for some iphlpapi.h functionality */
! 17: #define _WIN32_WINNT 0x0601
! 18: #include <winsock2.h>
! 19: #include <ws2ipdef.h>
! 20: #include <windows.h>
! 21: #include <ntddndis.h>
! 22: #include <naptypes.h>
! 23: #include <iphlpapi.h>
! 24:
! 25: #include "kernel_iph_net.h"
! 26:
! 27: #include <daemon.h>
! 28: #include <threading/mutex.h>
! 29: #include <collections/linked_list.h>
! 30: #include <processing/jobs/callback_job.h>
! 31:
! 32:
! 33: /** delay before firing roam events (ms) */
! 34: #define ROAM_DELAY 500
! 35:
! 36: typedef struct private_kernel_iph_net_t private_kernel_iph_net_t;
! 37:
! 38: /**
! 39: * Private data of kernel_iph_net implementation.
! 40: */
! 41: struct private_kernel_iph_net_t {
! 42:
! 43: /**
! 44: * Public interface.
! 45: */
! 46: kernel_iph_net_t public;
! 47:
! 48: /**
! 49: * NotifyIpInterfaceChange() handle
! 50: */
! 51: HANDLE changes;
! 52:
! 53: /**
! 54: * EnableRouter() OVERLAPPED
! 55: */
! 56: OVERLAPPED router;
! 57:
! 58: /**
! 59: * Mutex to access interface list
! 60: */
! 61: mutex_t *mutex;
! 62:
! 63: /**
! 64: * Known interfaces, as iface_t
! 65: */
! 66: linked_list_t *ifaces;
! 67:
! 68: /**
! 69: * Earliest time of the next roam event
! 70: */
! 71: timeval_t roam_next;
! 72:
! 73: /**
! 74: * Roam event due to address change?
! 75: */
! 76: bool roam_address;
! 77: };
! 78:
! 79: /**
! 80: * Interface entry
! 81: */
! 82: typedef struct {
! 83: /** interface index */
! 84: DWORD ifindex;
! 85: /** interface name */
! 86: char *ifname;
! 87: /** interface description */
! 88: char *ifdesc;
! 89: /** type of interface */
! 90: DWORD iftype;
! 91: /** interface status */
! 92: IF_OPER_STATUS status;
! 93: /** list of known addresses, as host_t */
! 94: linked_list_t *addrs;
! 95: } iface_t;
! 96:
! 97: /**
! 98: * Clean up an iface_t
! 99: */
! 100: static void iface_destroy(iface_t *this)
! 101: {
! 102: this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
! 103: free(this->ifname);
! 104: free(this->ifdesc);
! 105: free(this);
! 106: }
! 107:
! 108: /**
! 109: * Enum names for Windows IF_OPER_STATUS
! 110: */
! 111: ENUM(if_oper_names, IfOperStatusUp, IfOperStatusLowerLayerDown,
! 112: "Up",
! 113: "Down",
! 114: "Testing",
! 115: "Unknown",
! 116: "Dormant",
! 117: "NotPresent",
! 118: "LowerLayerDown",
! 119: );
! 120:
! 121: /**
! 122: * Callback function that raises the delayed roam event
! 123: */
! 124: static job_requeue_t roam_event(private_kernel_iph_net_t *this)
! 125: {
! 126: bool address;
! 127:
! 128: this->mutex->lock(this->mutex);
! 129: address = this->roam_address;
! 130: this->roam_address = FALSE;
! 131: this->mutex->unlock(this->mutex);
! 132:
! 133: charon->kernel->roam(charon->kernel, address);
! 134: return JOB_REQUEUE_NONE;
! 135: }
! 136:
! 137: /**
! 138: * Fire delayed roam event, caller should hold mutex
! 139: */
! 140: static void fire_roam_event(private_kernel_iph_net_t *this, bool address)
! 141: {
! 142: timeval_t now;
! 143:
! 144: time_monotonic(&now);
! 145: this->roam_address |= address;
! 146: if (timercmp(&now, &this->roam_next, >))
! 147: {
! 148: timeval_add_ms(&now, ROAM_DELAY);
! 149: this->roam_next = now;
! 150: lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
! 151: callback_job_create((callback_job_cb_t)roam_event,
! 152: this, NULL, NULL),
! 153: ROAM_DELAY);
! 154: }
! 155: }
! 156:
! 157: /**
! 158: * Update addresses for an iface entry
! 159: */
! 160: static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
! 161: IP_ADAPTER_ADDRESSES *addr, bool log)
! 162: {
! 163: IP_ADAPTER_UNICAST_ADDRESS *current;
! 164: enumerator_t *enumerator;
! 165: linked_list_t *list;
! 166: host_t *host, *old;
! 167: bool changes = FALSE;
! 168:
! 169: list = entry->addrs;
! 170: entry->addrs = linked_list_create();
! 171:
! 172: for (current = addr->FirstUnicastAddress; current; current = current->Next)
! 173: {
! 174: if (current->Address.lpSockaddr->sa_family == AF_INET6)
! 175: {
! 176: struct sockaddr_in6 *sin;
! 177:
! 178: sin = (struct sockaddr_in6*)current->Address.lpSockaddr;
! 179: if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
! 180: {
! 181: continue;
! 182: }
! 183: }
! 184:
! 185: host = host_create_from_sockaddr(current->Address.lpSockaddr);
! 186: if (host)
! 187: {
! 188: bool found = FALSE;
! 189:
! 190: enumerator = list->create_enumerator(list);
! 191: while (enumerator->enumerate(enumerator, &old))
! 192: {
! 193: if (host->ip_equals(host, old))
! 194: {
! 195: list->remove_at(list, enumerator);
! 196: old->destroy(old);
! 197: found = TRUE;
! 198: }
! 199: }
! 200: enumerator->destroy(enumerator);
! 201:
! 202: entry->addrs->insert_last(entry->addrs, host);
! 203:
! 204: if (!found && log)
! 205: {
! 206: DBG1(DBG_KNL, "%H appeared on interface %u '%s'",
! 207: host, entry->ifindex, entry->ifdesc);
! 208: changes = TRUE;
! 209: }
! 210: }
! 211: }
! 212:
! 213: while (list->remove_first(list, (void**)&old) == SUCCESS)
! 214: {
! 215: if (log)
! 216: {
! 217: DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
! 218: old, entry->ifindex, entry->ifdesc);
! 219: changes = TRUE;
! 220: }
! 221: old->destroy(old);
! 222: }
! 223: list->destroy(list);
! 224:
! 225: if (changes)
! 226: {
! 227: fire_roam_event(this, TRUE);
! 228: }
! 229: }
! 230:
! 231: /**
! 232: * Add an interface entry
! 233: */
! 234: static void add_interface(private_kernel_iph_net_t *this,
! 235: IP_ADAPTER_ADDRESSES *addr, bool log)
! 236: {
! 237: enumerator_t *enumerator;
! 238: iface_t *entry;
! 239: bool exists = FALSE;
! 240:
! 241: this->mutex->lock(this->mutex);
! 242: enumerator = this->ifaces->create_enumerator(this->ifaces);
! 243: while (enumerator->enumerate(enumerator, &entry))
! 244: {
! 245: if (entry->ifindex == addr->IfIndex)
! 246: {
! 247: exists = TRUE;
! 248: break;
! 249: }
! 250: }
! 251: enumerator->destroy(enumerator);
! 252: this->mutex->unlock(this->mutex);
! 253:
! 254: if (!exists)
! 255: {
! 256: char desc[128] = "";
! 257:
! 258: wcstombs(desc, addr->Description, sizeof(desc));
! 259:
! 260: INIT(entry,
! 261: .ifindex = addr->IfIndex,
! 262: .ifname = strdup(addr->AdapterName),
! 263: .ifdesc = strdup(desc),
! 264: .iftype = addr->IfType,
! 265: .status = addr->OperStatus,
! 266: .addrs = linked_list_create(),
! 267: );
! 268:
! 269: if (log)
! 270: {
! 271: DBG1(DBG_KNL, "interface %u '%s' appeared",
! 272: entry->ifindex, entry->ifdesc);
! 273: }
! 274:
! 275: this->mutex->lock(this->mutex);
! 276: update_addrs(this, entry, addr, log);
! 277: this->ifaces->insert_last(this->ifaces, entry);
! 278: this->mutex->unlock(this->mutex);
! 279: }
! 280: }
! 281:
! 282: /**
! 283: * Remove an interface entry that is gone
! 284: */
! 285: static void remove_interface(private_kernel_iph_net_t *this, NET_IFINDEX index)
! 286: {
! 287: enumerator_t *enumerator;
! 288: iface_t *entry;
! 289:
! 290: this->mutex->lock(this->mutex);
! 291: enumerator = this->ifaces->create_enumerator(this->ifaces);
! 292: while (enumerator->enumerate(enumerator, &entry))
! 293: {
! 294: if (entry->ifindex == index)
! 295: {
! 296: this->ifaces->remove_at(this->ifaces, enumerator);
! 297: DBG1(DBG_KNL, "interface %u '%s' disappeared",
! 298: entry->ifindex, entry->ifdesc);
! 299: iface_destroy(entry);
! 300: fire_roam_event(this, TRUE);
! 301: }
! 302: }
! 303: enumerator->destroy(enumerator);
! 304: this->mutex->unlock(this->mutex);
! 305: }
! 306:
! 307: /**
! 308: * Update an interface entry changed
! 309: */
! 310: static void update_interface(private_kernel_iph_net_t *this,
! 311: IP_ADAPTER_ADDRESSES *addr)
! 312: {
! 313: enumerator_t *enumerator;
! 314: iface_t *entry;
! 315:
! 316: this->mutex->lock(this->mutex);
! 317: enumerator = this->ifaces->create_enumerator(this->ifaces);
! 318: while (enumerator->enumerate(enumerator, &entry))
! 319: {
! 320: if (entry->ifindex == addr->IfIndex)
! 321: {
! 322: if (entry->status != addr->OperStatus)
! 323: {
! 324: DBG1(DBG_KNL, "interface %u '%s' changed state from %N to %N",
! 325: entry->ifindex, entry->ifdesc, if_oper_names,
! 326: entry->status, if_oper_names, addr->OperStatus);
! 327: entry->status = addr->OperStatus;
! 328: fire_roam_event(this, TRUE);
! 329: }
! 330: update_addrs(this, entry, addr, TRUE);
! 331: }
! 332: }
! 333: enumerator->destroy(enumerator);
! 334: this->mutex->unlock(this->mutex);
! 335: }
! 336:
! 337: /**
! 338: * MinGW gets MIB_IPINTERFACE_ROW wrong, as it packs InterfaceLuid just after
! 339: * Family. Fix that with our own version of the struct header.
! 340: */
! 341: typedef struct {
! 342: ADDRESS_FAMILY Family;
! 343: union {
! 344: ULONG64 Value;
! 345: struct {
! 346: ULONG64 Reserved :24;
! 347: ULONG64 NetLuidIndex :24;
! 348: ULONG64 IfType :16;
! 349: } Info;
! 350: } InterfaceLuid;
! 351: NET_IFINDEX InterfaceIndex;
! 352: /* more would go here if needed */
! 353: } MIB_IPINTERFACE_ROW_FIXUP;
! 354:
! 355: /**
! 356: * NotifyIpInterfaceChange() callback
! 357: */
! 358: static void WINAPI change_interface(void *user, PMIB_IPINTERFACE_ROW row_badal,
! 359: MIB_NOTIFICATION_TYPE type)
! 360: {
! 361: private_kernel_iph_net_t *this = user;
! 362: MIB_IPINTERFACE_ROW_FIXUP* row = (MIB_IPINTERFACE_ROW_FIXUP*)row_badal;
! 363: IP_ADAPTER_ADDRESSES addrs[64], *current;
! 364: ULONG res, size = sizeof(addrs);
! 365:
! 366: if (row && type == MibDeleteInstance)
! 367: {
! 368: remove_interface(this, row->InterfaceIndex);
! 369: }
! 370: else
! 371: {
! 372: res = GetAdaptersAddresses(AF_UNSPEC,
! 373: GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
! 374: GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
! 375: NULL, addrs, &size);
! 376: if (res == NO_ERROR)
! 377: {
! 378: current = addrs;
! 379: while (current)
! 380: {
! 381: /* row is NULL only on MibInitialNotification */
! 382: if (!row || row->InterfaceIndex == current->IfIndex)
! 383: {
! 384: switch (type)
! 385: {
! 386: case MibParameterNotification:
! 387: update_interface(this, current);
! 388: break;
! 389: case MibInitialNotification:
! 390: add_interface(this, current, FALSE);
! 391: break;
! 392: case MibAddInstance:
! 393: add_interface(this, current, TRUE);
! 394: break;
! 395: default:
! 396: break;
! 397: }
! 398: }
! 399: current = current->Next;
! 400: }
! 401: }
! 402: else
! 403: {
! 404: DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res);
! 405: }
! 406: }
! 407: }
! 408:
! 409: /**
! 410: * Get an iface entry for a local address, does no locking
! 411: */
! 412: static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip)
! 413: {
! 414: enumerator_t *ifaces, *addrs;
! 415: iface_t *entry, *found = NULL;
! 416: host_t *host;
! 417:
! 418: ifaces = this->ifaces->create_enumerator(this->ifaces);
! 419: while (!found && ifaces->enumerate(ifaces, &entry))
! 420: {
! 421: addrs = entry->addrs->create_enumerator(entry->addrs);
! 422: while (!found && addrs->enumerate(addrs, &host))
! 423: {
! 424: if (host->ip_equals(host, ip))
! 425: {
! 426: found = entry;
! 427: }
! 428: }
! 429: addrs->destroy(addrs);
! 430: }
! 431: ifaces->destroy(ifaces);
! 432:
! 433: return found;
! 434: }
! 435:
! 436: METHOD(kernel_net_t, get_interface_name, bool,
! 437: private_kernel_iph_net_t *this, host_t* ip, char **name)
! 438: {
! 439: iface_t *entry;
! 440:
! 441: this->mutex->lock(this->mutex);
! 442: entry = address2entry(this, ip);
! 443: if (entry && name)
! 444: {
! 445: *name = strdup(entry->ifname);
! 446: }
! 447: this->mutex->unlock(this->mutex);
! 448:
! 449: return entry != NULL;
! 450: }
! 451:
! 452: /**
! 453: * Address enumerator
! 454: */
! 455: typedef struct {
! 456: /** implements enumerator_t */
! 457: enumerator_t public;
! 458: /** what kind of address should we enumerate? */
! 459: kernel_address_type_t which;
! 460: /** enumerator over interfaces */
! 461: enumerator_t *ifaces;
! 462: /** current enumerator over addresses, or NULL */
! 463: enumerator_t *addrs;
! 464: /** mutex to unlock on destruction */
! 465: mutex_t *mutex;
! 466: } addr_enumerator_t;
! 467:
! 468: METHOD(enumerator_t, addr_enumerate, bool,
! 469: addr_enumerator_t *this, va_list args)
! 470: {
! 471: iface_t *entry;
! 472: host_t **host;
! 473:
! 474: VA_ARGS_VGET(args, host);
! 475:
! 476: while (TRUE)
! 477: {
! 478: while (!this->addrs)
! 479: {
! 480: if (!this->ifaces->enumerate(this->ifaces, &entry))
! 481: {
! 482: return FALSE;
! 483: }
! 484: if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK &&
! 485: !(this->which & ADDR_TYPE_LOOPBACK))
! 486: {
! 487: continue;
! 488: }
! 489: if (entry->status != IfOperStatusUp &&
! 490: !(this->which & ADDR_TYPE_DOWN))
! 491: {
! 492: continue;
! 493: }
! 494: this->addrs = entry->addrs->create_enumerator(entry->addrs);
! 495: }
! 496: if (this->addrs->enumerate(this->addrs, host))
! 497: {
! 498: return TRUE;
! 499: }
! 500: this->addrs->destroy(this->addrs);
! 501: this->addrs = NULL;
! 502: }
! 503: }
! 504:
! 505: METHOD(enumerator_t, addr_destroy, void,
! 506: addr_enumerator_t *this)
! 507: {
! 508: DESTROY_IF(this->addrs);
! 509: this->ifaces->destroy(this->ifaces);
! 510: this->mutex->unlock(this->mutex);
! 511: free(this);
! 512: }
! 513:
! 514: METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
! 515: private_kernel_iph_net_t *this, kernel_address_type_t which)
! 516: {
! 517: addr_enumerator_t *enumerator;
! 518:
! 519: if (!(which & ADDR_TYPE_REGULAR))
! 520: {
! 521: /* we currently have no virtual, but regular IPs only */
! 522: return enumerator_create_empty();
! 523: }
! 524:
! 525: this->mutex->lock(this->mutex);
! 526:
! 527: INIT(enumerator,
! 528: .public = {
! 529: .enumerate = enumerator_enumerate_default,
! 530: .venumerate = _addr_enumerate,
! 531: .destroy = _addr_destroy,
! 532: },
! 533: .which = which,
! 534: .ifaces = this->ifaces->create_enumerator(this->ifaces),
! 535: .mutex = this->mutex,
! 536: );
! 537: return &enumerator->public;
! 538: }
! 539:
! 540: METHOD(kernel_net_t, get_source_addr, host_t*,
! 541: private_kernel_iph_net_t *this, host_t *dest, host_t *src)
! 542: {
! 543: MIB_IPFORWARD_ROW2 route;
! 544: SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
! 545: DWORD res, index = 0;
! 546:
! 547: res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
! 548: if (res != NO_ERROR)
! 549: {
! 550: DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
! 551: return NULL;
! 552: }
! 553:
! 554: sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
! 555: if (src)
! 556: {
! 557: sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
! 558: }
! 559: res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
! 560: if (res != NO_ERROR)
! 561: {
! 562: DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res);
! 563: return NULL;
! 564: }
! 565: return host_create_from_sockaddr((struct sockaddr*)&best);
! 566: }
! 567:
! 568: METHOD(kernel_net_t, get_nexthop, host_t*,
! 569: private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src,
! 570: char **iface)
! 571: {
! 572: MIB_IPFORWARD_ROW2 route;
! 573: SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
! 574: DWORD res, index = 0;
! 575: host_t *nexthop;
! 576:
! 577: res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
! 578: if (res != NO_ERROR)
! 579: {
! 580: DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
! 581: return NULL;
! 582: }
! 583:
! 584: sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
! 585: if (src)
! 586: {
! 587: sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
! 588: }
! 589: res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
! 590: if (res != NO_ERROR)
! 591: {
! 592: DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res);
! 593: return NULL;
! 594: }
! 595: nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop);
! 596: if (nexthop)
! 597: {
! 598: if (!nexthop->is_anyaddr(nexthop))
! 599: {
! 600: if (iface)
! 601: {
! 602: *iface = NULL;
! 603: }
! 604: return nexthop;
! 605: }
! 606: nexthop->destroy(nexthop);
! 607: }
! 608: return NULL;
! 609: }
! 610:
! 611: METHOD(kernel_net_t, add_ip, status_t,
! 612: private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
! 613: char *iface_name)
! 614: {
! 615: return NOT_SUPPORTED;
! 616: }
! 617:
! 618: METHOD(kernel_net_t, del_ip, status_t,
! 619: private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
! 620: bool wait)
! 621: {
! 622: return NOT_SUPPORTED;
! 623: }
! 624:
! 625: /**
! 626: * Add or remove a route
! 627: */
! 628: static status_t manage_route(private_kernel_iph_net_t *this, bool add,
! 629: chunk_t dst, uint8_t prefixlen, host_t *gtw, char *name)
! 630: {
! 631: MIB_IPFORWARD_ROW2 row = {
! 632: .DestinationPrefix = {
! 633: .PrefixLength = prefixlen,
! 634: },
! 635: .SitePrefixLength = prefixlen,
! 636: .ValidLifetime = INFINITE,
! 637: .PreferredLifetime = INFINITE,
! 638: .Metric = 10,
! 639: .Protocol = MIB_IPPROTO_NETMGMT,
! 640: };
! 641: enumerator_t *enumerator;
! 642: iface_t *entry;
! 643: ULONG ret;
! 644:
! 645: this->mutex->lock(this->mutex);
! 646: enumerator = this->ifaces->create_enumerator(this->ifaces);
! 647: while (enumerator->enumerate(enumerator, &entry))
! 648: {
! 649: if (streq(name, entry->ifname))
! 650: {
! 651: row.InterfaceIndex = entry->ifindex;
! 652: break;
! 653: }
! 654: }
! 655: enumerator->destroy(enumerator);
! 656: this->mutex->unlock(this->mutex);
! 657:
! 658: if (!row.InterfaceIndex)
! 659: {
! 660: return NOT_FOUND;
! 661: }
! 662: switch (dst.len)
! 663: {
! 664: case 4:
! 665: row.DestinationPrefix.Prefix.si_family = AF_INET;
! 666: memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr,
! 667: dst.ptr, dst.len);
! 668: break;
! 669: case 16:
! 670: row.DestinationPrefix.Prefix.si_family = AF_INET6;
! 671: memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr,
! 672: dst.ptr, dst.len);
! 673: break;
! 674: default:
! 675: return FAILED;
! 676: }
! 677: if (gtw)
! 678: {
! 679: memcpy(&row.NextHop, gtw->get_sockaddr(gtw),
! 680: *gtw->get_sockaddr_len(gtw));
! 681: }
! 682:
! 683: if (add)
! 684: {
! 685: ret = CreateIpForwardEntry2(&row);
! 686: }
! 687: else
! 688: {
! 689: ret = DeleteIpForwardEntry2(&row);
! 690: }
! 691: if (ret != NO_ERROR)
! 692: {
! 693: DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret);
! 694: return FAILED;
! 695: }
! 696:
! 697: if (add)
! 698: {
! 699: ret = EnableRouter(NULL, &this->router);
! 700: if (ret != ERROR_IO_PENDING)
! 701: {
! 702: DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret);
! 703: }
! 704: }
! 705: else
! 706: {
! 707: ret = UnenableRouter(&this->router, NULL);
! 708: if (ret != NO_ERROR)
! 709: {
! 710: DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret);
! 711: }
! 712: }
! 713: return SUCCESS;
! 714: }
! 715:
! 716: METHOD(kernel_net_t, add_route, status_t,
! 717: private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
! 718: host_t *gateway, host_t *src, char *name, bool pass)
! 719: {
! 720: return manage_route(this, TRUE, dst, prefixlen, gateway, name);
! 721: }
! 722:
! 723: METHOD(kernel_net_t, del_route, status_t,
! 724: private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
! 725: host_t *gateway, host_t *src, char *name, bool pass)
! 726: {
! 727: return manage_route(this, FALSE, dst, prefixlen, gateway, name);
! 728: }
! 729:
! 730: METHOD(kernel_net_t, destroy, void,
! 731: private_kernel_iph_net_t *this)
! 732: {
! 733: if (this->changes)
! 734: {
! 735: CancelMibChangeNotify2(this->changes);
! 736: }
! 737: CloseHandle(this->router.hEvent);
! 738: this->mutex->destroy(this->mutex);
! 739: this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy);
! 740: free(this);
! 741: }
! 742:
! 743: /*
! 744: * Described in header.
! 745: */
! 746: kernel_iph_net_t *kernel_iph_net_create()
! 747: {
! 748: private_kernel_iph_net_t *this;
! 749: ULONG res;
! 750:
! 751: INIT(this,
! 752: .public = {
! 753: .interface = {
! 754: .get_interface = _get_interface_name,
! 755: .create_address_enumerator = _create_address_enumerator,
! 756: .get_source_addr = _get_source_addr,
! 757: .get_nexthop = _get_nexthop,
! 758: .add_ip = _add_ip,
! 759: .del_ip = _del_ip,
! 760: .add_route = _add_route,
! 761: .del_route = _del_route,
! 762: .destroy = _destroy,
! 763: },
! 764: },
! 765: .router = {
! 766: .hEvent = CreateEvent(NULL, FALSE, FALSE, NULL),
! 767: },
! 768: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 769: .ifaces = linked_list_create(),
! 770: );
! 771: /* PIPINTERFACE_CHANGE_CALLBACK is not using WINAPI in MinGW, which seems
! 772: * to be wrong. Force a cast to our WINAPI call */
! 773: res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface,
! 774: this, TRUE, &this->changes);
! 775: if (res != NO_ERROR)
! 776: {
! 777: DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx",
! 778: res);
! 779: destroy(this);
! 780: return NULL;
! 781: }
! 782:
! 783: return &this->public;
! 784: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>