darwin-xnu/bsd/net/kpi_interface.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22
  23#include "kpi_interface.h"
  24
  25#include <sys/queue.h>
  26#include <sys/param.h>  /* for definition of NULL */
  27#include <sys/errno.h>
  28#include <sys/socket.h>
  29#include <sys/kern_event.h>
  30#include <sys/kernel.h>
  31#include <sys/malloc.h>
  32#include <sys/kpi_mbuf.h>
  33#include <net/if_var.h>
  34#include <net/if_dl.h>
  35#include <net/dlil.h>
  36#include <net/if_types.h>
  37#include <net/if_dl.h>
  38#include <net/if_arp.h>
  39#include <libkern/libkern.h>
  40#include <kern/locks.h>
  41
  42#if IF_LASTCHANGEUPTIME
  43#define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange)
  44#else
  45#define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange)
  46#endif
  47
  48extern lck_spin_t *dlil_input_lock;
  49
  50/*
  51        Temporary work around until we have real reference counting
  52        
  53        We keep the bits about calling dlil_if_release (which should be
  54        called recycle) transparent by calling it from our if_free function
  55        pointer. We have to keep the client's original detach function
  56        somewhere so we can call it.
  57 */
  58static void
  59ifnet_kpi_free(
  60        ifnet_t ifp)
  61{
  62        ifnet_detached_func     detach_func = ifp->if_kpi_storage;
  63        
  64        if (detach_func)
  65                detach_func(ifp);
  66        
  67        if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
  68                FREE(ifp->if_broadcast.u.ptr, M_IFADDR);
  69                ifp->if_broadcast.u.ptr = NULL;
  70        }
  71        
  72        dlil_if_release(ifp);
  73}
  74
  75errno_t
  76ifnet_allocate(
  77        const struct ifnet_init_params *init,
  78        ifnet_t *interface)
  79{
  80        int error;
  81        struct ifnet *ifp = NULL;
  82        
  83        if (init->family == 0)
  84                return EINVAL;
  85        if (init->name == NULL ||
  86                init->output == NULL)
  87                return EINVAL;
  88        if (strlen(init->name) >= IFNAMSIZ)
  89                return EINVAL;
  90        if ((init->type & 0xFFFFFF00) != 0 || init->type == 0)
  91                return EINVAL;
  92        
  93        error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp);
  94        if (error == 0)
  95        {               
  96                strncpy(ifp->if_name, init->name, IFNAMSIZ);
  97                ifp->if_type = init->type;
  98                ifp->if_family = init->family;
  99                ifp->if_unit = init->unit;
 100                ifp->if_output = init->output;
 101                ifp->if_demux = init->demux;
 102                ifp->if_add_proto_u.kpi = init->add_proto;
 103                ifp->if_del_proto = init->del_proto;
 104                ifp->if_check_multi = init->check_multi;
 105                ifp->if_framer = init->framer;
 106                ifp->if_softc = init->softc;
 107                ifp->if_ioctl = init->ioctl;
 108                ifp->if_set_bpf_tap = init->set_bpf_tap;
 109                ifp->if_free = ifnet_kpi_free;
 110                ifp->if_event = init->event;
 111                ifp->if_kpi_storage = init->detach;
 112                ifp->if_eflags |= IFEF_USEKPI;
 113                
 114                if (init->broadcast_len && init->broadcast_addr) {
 115                        if (init->broadcast_len > sizeof(ifp->if_broadcast.u.buffer)) {
 116                                MALLOC(ifp->if_broadcast.u.ptr, u_char*, init->broadcast_len, M_IFADDR, M_NOWAIT);
 117                                if (ifp->if_broadcast.u.ptr == NULL) {
 118                                        error = ENOMEM;
 119                                }
 120                                else {
 121                                        bcopy(init->broadcast_addr, ifp->if_broadcast.u.ptr, init->broadcast_len);
 122                                }
 123                        }
 124                        else {
 125                                bcopy(init->broadcast_addr, ifp->if_broadcast.u.buffer, init->broadcast_len);
 126                        }
 127                        ifp->if_broadcast.length = init->broadcast_len;
 128                }
 129                else {
 130                        bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
 131                }
 132                
 133                if (error == 0) {
 134                        *interface = ifp;
 135                        ifnet_reference(ifp); // temporary - this should be done in dlil_if_acquire
 136                }
 137                else {
 138                        dlil_if_release(ifp);
 139                        *interface = 0;
 140                }
 141        }
 142        
 143        /*
 144          Note: We should do something here to indicate that we haven't been
 145          attached yet. By doing so, we can catch the case in ifnet_release
 146          where the reference count reaches zero and call the recycle
 147          function. If the interface is attached, the interface will be
 148          recycled when the interface's if_free function is called. If the
 149          interface is never attached, the if_free function will never be
 150          called and the interface will never be recycled.
 151        */
 152        
 153        return error;
 154}
 155
 156errno_t
 157ifnet_reference(
 158        ifnet_t interface)
 159{
 160        if (interface == NULL) return EINVAL;
 161        ifp_reference(interface);
 162        return 0;
 163}
 164
 165errno_t
 166ifnet_release(
 167        ifnet_t interface)
 168{
 169        if (interface == NULL) return EINVAL;
 170        ifp_release(interface);
 171        return 0;
 172}
 173
 174errno_t
 175ifnet_attach(
 176        ifnet_t interface,
 177        const struct sockaddr_dl *ll_addr)
 178{
 179        if (interface == NULL) return EINVAL;
 180        if (ll_addr && interface->if_addrlen == 0) {
 181                interface->if_addrlen = ll_addr->sdl_alen;
 182        }
 183        else if (ll_addr && ll_addr->sdl_alen != interface->if_addrlen) {
 184                return EINVAL;
 185        }
 186        return dlil_if_attach_with_address(interface, ll_addr);
 187}
 188
 189errno_t
 190ifnet_detach(
 191        ifnet_t interface)
 192{
 193        errno_t error;
 194        
 195        if (interface == NULL) return EINVAL;
 196        
 197        error = dlil_if_detach(interface);
 198        if (error == DLIL_WAIT_FOR_FREE) error = 0; /* Client should always wait for detach */
 199        
 200        return error;
 201}
 202
 203void*
 204ifnet_softc(
 205        ifnet_t interface)
 206{
 207        return interface == NULL ? NULL : interface->if_softc;
 208}
 209
 210const char*
 211ifnet_name(
 212        ifnet_t interface)
 213{
 214        return interface == NULL ? NULL : interface->if_name;
 215}
 216
 217ifnet_family_t
 218ifnet_family(
 219        ifnet_t interface)
 220{
 221        return interface == NULL ? 0 : interface->if_family;
 222}
 223
 224u_int32_t
 225ifnet_unit(
 226        ifnet_t interface)
 227{
 228        return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
 229}
 230
 231u_int32_t
 232ifnet_index(
 233        ifnet_t interface)
 234{
 235        return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
 236}
 237
 238errno_t
 239ifnet_set_flags(
 240        ifnet_t interface,
 241        u_int16_t new_flags,
 242        u_int16_t mask)
 243{
 244        int lock;
 245        
 246        if (interface == NULL) return EINVAL;
 247        lock = (interface->if_lock != 0);
 248        
 249        if (lock) ifnet_lock_exclusive(interface);
 250        
 251        /* If we are modifying the up/down state, call if_updown */
 252        if (lock && (mask & IFF_UP) != 0) {
 253                if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
 254        }
 255        
 256        interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
 257        if (lock) ifnet_lock_done(interface);
 258        
 259        return 0;
 260}
 261
 262u_int16_t
 263ifnet_flags(
 264        ifnet_t interface)
 265{
 266        return interface == NULL ? 0 : interface->if_flags;
 267}
 268
 269errno_t
 270ifnet_set_eflags(
 271        ifnet_t interface,
 272        u_int32_t new_flags,
 273        u_int32_t mask)
 274{
 275        int lock;
 276        
 277        if (interface == NULL) return EINVAL;
 278        lock = (interface->if_lock != 0);
 279        
 280        if (lock) ifnet_lock_exclusive(interface);
 281        interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask);
 282        if (lock) ifnet_lock_done(interface);
 283        
 284        return 0;
 285}
 286
 287u_int32_t
 288ifnet_eflags(
 289        ifnet_t interface)
 290{
 291        return interface == NULL ? 0 : interface->if_eflags;
 292}
 293
 294static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
 295                        IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
 296                        IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU;
 297
 298errno_t
 299ifnet_set_offload(
 300        ifnet_t interface,
 301        ifnet_offload_t offload)
 302{
 303        int lock;
 304        
 305        if (interface == NULL) return EINVAL;
 306        lock = (interface->if_lock != 0);
 307        
 308        if (lock) ifnet_lock_exclusive(interface);
 309        interface->if_hwassist = (offload & offload_mask);
 310        if (lock) ifnet_lock_done(interface);
 311        
 312        return 0;
 313}
 314
 315ifnet_offload_t
 316ifnet_offload(
 317        ifnet_t interface)
 318{
 319        return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
 320}
 321
 322/*
 323 * Should MIB data store a copy?
 324 */
 325errno_t
 326ifnet_set_link_mib_data(
 327        ifnet_t interface,
 328        void* mibData,
 329        u_int32_t mibLen)
 330{
 331        int lock;
 332        
 333        if (interface == NULL) return EINVAL;
 334        lock = (interface->if_lock != 0);
 335        
 336        if (lock) ifnet_lock_exclusive(interface);
 337        interface->if_linkmib = (void*)mibData;
 338        interface->if_linkmiblen = mibLen;
 339        if (lock) ifnet_lock_done(interface);
 340        return 0;
 341}
 342
 343errno_t
 344ifnet_get_link_mib_data(
 345        ifnet_t interface,
 346        void *mibData,
 347        u_int32_t *mibLen)
 348{
 349        errno_t result = 0;
 350        int lock;
 351        
 352        if (interface == NULL) return EINVAL;
 353        lock = (interface->if_lock != NULL);
 354        
 355        if (lock) ifnet_lock_shared(interface);
 356        if (*mibLen < interface->if_linkmiblen)
 357                result = EMSGSIZE;
 358        if (result == 0 && interface->if_linkmib == NULL)
 359                result = ENOTSUP;
 360        
 361        if (result == 0) {
 362                *mibLen = interface->if_linkmiblen;
 363                bcopy(interface->if_linkmib, mibData, *mibLen);
 364        }
 365        if (lock) ifnet_lock_done(interface);
 366        
 367        return result;
 368}
 369
 370u_int32_t
 371ifnet_get_link_mib_data_length(
 372        ifnet_t interface)
 373{
 374        return interface == NULL ? 0 : interface->if_linkmiblen;
 375}
 376
 377errno_t
 378ifnet_attach_protocol(
 379        ifnet_t interface,
 380        protocol_family_t protocol,
 381        const struct ifnet_attach_proto_param *proto_details)
 382{
 383        if (interface == NULL || protocol == 0 || proto_details == NULL)
 384                return EINVAL;
 385        return dlil_attach_protocol_kpi(interface, protocol, proto_details);
 386}
 387
 388errno_t
 389ifnet_detach_protocol(
 390        ifnet_t interface,
 391        protocol_family_t protocol)
 392{
 393        if (interface == NULL || protocol == 0) return EINVAL;
 394        return dlil_detach_protocol(interface, protocol);
 395}
 396
 397errno_t
 398ifnet_output(
 399        ifnet_t interface,
 400        protocol_family_t protocol_family,
 401        mbuf_t m,
 402        void *route,
 403        const struct sockaddr *dest)
 404{
 405        if (interface == NULL || protocol_family == 0 || m == NULL) {
 406                if (m)
 407                        mbuf_freem_list(m);
 408                return EINVAL;
 409        }
 410        return dlil_output(interface, protocol_family, m, route, dest, 0);
 411}
 412
 413errno_t
 414ifnet_output_raw(
 415        ifnet_t interface,
 416        protocol_family_t protocol_family,
 417        mbuf_t m)
 418{
 419        if (interface == NULL || protocol_family == 0 || m == NULL) {
 420                if (m)
 421                        mbuf_freem_list(m);
 422                return EINVAL;
 423        }
 424        return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
 425}
 426
 427errno_t
 428ifnet_input(
 429        ifnet_t interface,
 430        mbuf_t first_packet,
 431        const struct ifnet_stat_increment_param *stats)
 432{
 433        mbuf_t  last_packet = first_packet;
 434        
 435        if (interface == NULL || first_packet == NULL) {
 436                if (first_packet)
 437                        mbuf_freem_list(first_packet);
 438                return EINVAL;
 439        }
 440        
 441        while (mbuf_nextpkt(last_packet) != NULL)
 442                last_packet = mbuf_nextpkt(last_packet);
 443        return dlil_input_with_stats(interface, first_packet, last_packet, stats);
 444}
 445
 446errno_t
 447ifnet_ioctl(
 448        ifnet_t interface,
 449        protocol_family_t       protocol_family,
 450        u_int32_t ioctl_code,
 451        void *ioctl_arg)
 452{
 453        if (interface == NULL || protocol_family == 0 || ioctl_code == 0)
 454                return EINVAL;
 455        return dlil_ioctl(protocol_family, interface,
 456                                          ioctl_code, ioctl_arg);
 457}
 458
 459errno_t
 460ifnet_event(
 461        ifnet_t interface,
 462        struct kern_event_msg* event_ptr)
 463{
 464        if (interface == NULL || event_ptr == NULL) return EINVAL;
 465        return dlil_event(interface, event_ptr);
 466}
 467
 468errno_t
 469ifnet_set_mtu(
 470        ifnet_t interface,
 471        u_int32_t mtu)
 472{
 473        if (interface == NULL) return EINVAL;
 474        interface->if_data.ifi_mtu = mtu;
 475        return 0;
 476}
 477
 478u_int32_t
 479ifnet_mtu(
 480        ifnet_t interface)
 481{
 482        u_int32_t retval;
 483        retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
 484        return retval;
 485}
 486
 487u_char
 488ifnet_type(
 489        ifnet_t interface)
 490{
 491        u_char retval;
 492        
 493        retval = interface == NULL ? 0 : interface->if_data.ifi_type;
 494        return retval;
 495}
 496
 497#if 0
 498errno_t
 499ifnet_set_typelen(
 500        ifnet_t interface,
 501        u_char typelen)
 502{
 503        int lock = (interface->if_lock != 0);
 504        if (lock) ifnet_lock_exclusive(interface);
 505        interface->if_data.ifi_typelen = typelen;
 506        if (lock) ifnet_lock_done(interface);
 507        return 0;
 508}
 509
 510u_char
 511ifnet_typelen(
 512        ifnet_t interface)
 513{
 514        u_char retval;
 515        retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
 516        return retval;
 517}
 518#endif
 519
 520errno_t
 521ifnet_set_addrlen(
 522        ifnet_t interface,
 523        u_char addrlen)
 524{
 525        if (interface == NULL) return EINVAL;
 526        interface->if_data.ifi_addrlen = addrlen;
 527        return 0;
 528}
 529
 530u_char
 531ifnet_addrlen(
 532        ifnet_t interface)
 533{
 534        u_char retval;
 535        retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
 536        return retval;
 537}
 538
 539errno_t
 540ifnet_set_hdrlen(
 541        ifnet_t interface,
 542        u_char hdrlen)
 543{
 544        if (interface == NULL) return EINVAL;
 545        interface->if_data.ifi_hdrlen = hdrlen;
 546        return 0;
 547}
 548
 549u_char
 550ifnet_hdrlen(
 551        ifnet_t interface)
 552{
 553        u_char retval;
 554        retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
 555        return retval;
 556}
 557
 558errno_t
 559ifnet_set_metric(
 560        ifnet_t interface,
 561        u_int32_t metric)
 562{
 563        if (interface == NULL) return EINVAL;
 564        interface->if_data.ifi_metric = metric;
 565        return 0;
 566}
 567
 568u_int32_t
 569ifnet_metric(
 570        ifnet_t interface)
 571{
 572        u_int32_t retval;
 573        retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
 574        return retval;
 575}
 576
 577errno_t
 578ifnet_set_baudrate(
 579        ifnet_t interface,
 580        u_int64_t baudrate)
 581{
 582        if (interface == NULL) return EINVAL;
 583        /* Pin baudrate to 32 bits until we can change the storage size */
 584        interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate;
 585        return 0;
 586}
 587
 588u_int64_t
 589ifnet_baudrate(
 590        ifnet_t interface)
 591{
 592        u_int64_t retval;
 593        retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
 594        return retval;
 595}
 596
 597errno_t
 598ifnet_stat_increment(
 599        ifnet_t interface,
 600        const struct ifnet_stat_increment_param *counts)
 601{
 602        if (interface == NULL) return EINVAL;
 603        
 604        lck_spin_lock(dlil_input_lock);
 605
 606        interface->if_data.ifi_ipackets += counts->packets_in;
 607        interface->if_data.ifi_ibytes += counts->bytes_in;
 608        interface->if_data.ifi_ierrors += counts->errors_in;
 609
 610        interface->if_data.ifi_opackets += counts->packets_out;
 611        interface->if_data.ifi_obytes += counts->bytes_out;
 612        interface->if_data.ifi_oerrors += counts->errors_out;
 613
 614        interface->if_data.ifi_collisions += counts->collisions;
 615        interface->if_data.ifi_iqdrops += counts->dropped;
 616        
 617        /* Touch the last change time. */
 618        TOUCHLASTCHANGE(&interface->if_lastchange);
 619
 620        lck_spin_unlock(dlil_input_lock);
 621        
 622        return 0;
 623}
 624
 625errno_t
 626ifnet_stat_increment_in(
 627        ifnet_t interface,
 628        u_int32_t packets_in,
 629        u_int32_t bytes_in,
 630        u_int32_t errors_in)
 631{
 632        if (interface == NULL) return EINVAL;
 633        
 634        lck_spin_lock(dlil_input_lock);
 635
 636        interface->if_data.ifi_ipackets += packets_in;
 637        interface->if_data.ifi_ibytes += bytes_in;
 638        interface->if_data.ifi_ierrors += errors_in;
 639
 640        TOUCHLASTCHANGE(&interface->if_lastchange);
 641
 642        lck_spin_unlock(dlil_input_lock);
 643        
 644        return 0;
 645}
 646
 647errno_t
 648ifnet_stat_increment_out(
 649        ifnet_t interface,
 650        u_int32_t packets_out,
 651        u_int32_t bytes_out,
 652        u_int32_t errors_out)
 653{
 654        if (interface == NULL) return EINVAL;
 655        
 656        lck_spin_lock(dlil_input_lock);
 657
 658        interface->if_data.ifi_opackets += packets_out;
 659        interface->if_data.ifi_obytes += bytes_out;
 660        interface->if_data.ifi_oerrors += errors_out;
 661
 662        TOUCHLASTCHANGE(&interface->if_lastchange);
 663
 664        lck_spin_unlock(dlil_input_lock);
 665        
 666        return 0;
 667}
 668
 669errno_t
 670ifnet_set_stat(
 671        ifnet_t interface,
 672        const struct ifnet_stats_param *stats)
 673{
 674        if (interface == NULL) return EINVAL;
 675        
 676        lck_spin_lock(dlil_input_lock);
 677
 678        interface->if_data.ifi_ipackets = stats->packets_in;
 679        interface->if_data.ifi_ibytes = stats->bytes_in;
 680        interface->if_data.ifi_imcasts = stats->multicasts_in;
 681        interface->if_data.ifi_ierrors = stats->errors_in;
 682        
 683        interface->if_data.ifi_opackets = stats->packets_out;
 684        interface->if_data.ifi_obytes = stats->bytes_out;
 685        interface->if_data.ifi_omcasts = stats->multicasts_out;
 686        interface->if_data.ifi_oerrors = stats->errors_out;
 687        
 688        interface->if_data.ifi_collisions = stats->collisions;
 689        interface->if_data.ifi_iqdrops = stats->dropped;
 690        interface->if_data.ifi_noproto = stats->no_protocol;
 691
 692        /* Touch the last change time. */
 693        TOUCHLASTCHANGE(&interface->if_lastchange);
 694
 695        lck_spin_unlock(dlil_input_lock);
 696        
 697        return 0;
 698}
 699
 700errno_t
 701ifnet_stat(
 702        ifnet_t interface,
 703        struct ifnet_stats_param *stats)
 704{
 705        if (interface == NULL) return EINVAL;
 706        
 707        lck_spin_lock(dlil_input_lock);
 708
 709        stats->packets_in = interface->if_data.ifi_ipackets;
 710        stats->bytes_in = interface->if_data.ifi_ibytes;
 711        stats->multicasts_in = interface->if_data.ifi_imcasts;
 712        stats->errors_in = interface->if_data.ifi_ierrors;
 713
 714        stats->packets_out = interface->if_data.ifi_opackets;
 715        stats->bytes_out = interface->if_data.ifi_obytes;
 716        stats->multicasts_out = interface->if_data.ifi_omcasts;
 717        stats->errors_out = interface->if_data.ifi_oerrors;
 718
 719        stats->collisions = interface->if_data.ifi_collisions;
 720        stats->dropped = interface->if_data.ifi_iqdrops;
 721        stats->no_protocol = interface->if_data.ifi_noproto;
 722
 723        lck_spin_unlock(dlil_input_lock);
 724        
 725        return 0;
 726}
 727
 728errno_t
 729ifnet_touch_lastchange(
 730        ifnet_t interface)
 731{
 732        if (interface == NULL) return EINVAL;
 733        
 734        lck_spin_lock(dlil_input_lock);
 735        TOUCHLASTCHANGE(&interface->if_lastchange);
 736        lck_spin_unlock(dlil_input_lock);
 737        
 738        return 0;
 739}
 740
 741errno_t
 742ifnet_lastchange(
 743        ifnet_t interface,
 744        struct timeval *last_change)
 745{
 746        if (interface == NULL) return EINVAL;
 747        
 748        lck_spin_lock(dlil_input_lock);
 749        *last_change = interface->if_data.ifi_lastchange;
 750        lck_spin_unlock(dlil_input_lock);
 751        
 752#if IF_LASTCHANGEUPTIME
 753        /* Crude conversion from uptime to calendar time */
 754        last_change->tv_sec += boottime_sec();
 755#endif
 756
 757        return 0;
 758}
 759
 760errno_t
 761ifnet_get_address_list(
 762        ifnet_t interface,
 763        ifaddr_t **addresses)
 764{
 765        if (interface == NULL || addresses == NULL) return EINVAL;
 766        return ifnet_get_address_list_family(interface, addresses, 0);
 767}
 768
 769errno_t
 770ifnet_get_address_list_family(
 771        ifnet_t interface,
 772        ifaddr_t **addresses,
 773        sa_family_t     family)
 774{
 775        struct ifnet *ifp;
 776        int count = 0;
 777        int cmax = 0;
 778        
 779        if (interface == NULL || addresses == NULL) return EINVAL;
 780        *addresses = NULL;
 781        
 782        ifnet_head_lock_shared();
 783        TAILQ_FOREACH(ifp, &ifnet, if_link)
 784        {
 785                if (interface && ifp != interface) continue;
 786                
 787                ifnet_lock_shared(ifp);
 788                if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
 789                        if (interface == NULL || interface == ifp)
 790                        {
 791                                struct ifaddr *addr;
 792                                TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
 793                                {
 794                                        if (family == 0 || addr->ifa_addr->sa_family == family)
 795                                                cmax++;
 796                                }
 797                        }
 798                }
 799                else if (interface != NULL) {
 800                        ifnet_lock_done(ifp);
 801                        ifnet_head_done();
 802                        return ENXIO;
 803                }
 804                ifnet_lock_done(ifp);
 805        }
 806        
 807        MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
 808        if (*addresses == NULL) {
 809                ifnet_head_done();
 810                return ENOMEM;
 811        }
 812        
 813        TAILQ_FOREACH(ifp, &ifnet, if_link)
 814        {
 815                if (interface && ifp != interface) continue;
 816                
 817                ifnet_lock_shared(ifp);
 818                if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
 819                        if (interface == NULL || (struct ifnet*)interface == ifp)
 820                        {
 821                                struct ifaddr *addr;
 822                                TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
 823                                {
 824                                        if (count + 1 > cmax) break;
 825                                        if (family == 0 || addr->ifa_addr->sa_family == family) {
 826                                                (*addresses)[count] = (ifaddr_t)addr;
 827                                                ifaddr_reference((*addresses)[count]);
 828                                                count++;
 829                                        }
 830                                }
 831                        }
 832                }
 833                ifnet_lock_done(ifp);
 834                if (interface || count == cmax)
 835                        break;
 836        }
 837        ifnet_head_done();
 838        (*addresses)[cmax] = 0;
 839        
 840        return 0;
 841}
 842
 843void
 844ifnet_free_address_list(
 845        ifaddr_t *addresses)
 846{
 847        int i;
 848        
 849        if (addresses == NULL) return;
 850        
 851        for (i = 0; addresses[i] != NULL; i++)
 852        {
 853                ifaddr_release(addresses[i]);
 854        }
 855        
 856        FREE(addresses, M_TEMP);
 857}
 858
 859void*
 860ifnet_lladdr(
 861        ifnet_t interface)
 862{
 863        if (interface == NULL) return NULL;
 864        return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr));
 865}
 866
 867errno_t
 868ifnet_llbroadcast_copy_bytes(
 869        ifnet_t interface,
 870        void    *addr,
 871        size_t  buffer_len,
 872        size_t  *out_len)
 873{
 874        if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL;
 875        
 876        *out_len = interface->if_broadcast.length;
 877        
 878        if (buffer_len < interface->if_broadcast.length) {
 879                return EMSGSIZE;
 880        }
 881        
 882        if (interface->if_broadcast.length == 0)
 883                return ENXIO;
 884        
 885        if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) {
 886                bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length);
 887        }
 888        else {
 889                bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
 890        }
 891        
 892        return 0;
 893}
 894
 895errno_t
 896ifnet_lladdr_copy_bytes(
 897        ifnet_t interface,
 898        void*   lladdr,
 899        size_t  lladdr_len)
 900{
 901        struct sockaddr_dl *sdl;
 902        if (interface == NULL || lladdr == NULL) return EINVAL;
 903        
 904        sdl = SDL(interface->if_addrhead.tqh_first->ifa_addr);
 905        
 906        while (1) {
 907                if (lladdr_len != sdl->sdl_alen) {
 908                        bzero(lladdr, lladdr_len);
 909                        return EMSGSIZE;
 910                }
 911                bcopy(LLADDR(sdl), lladdr, lladdr_len);
 912                if (bcmp(lladdr, LLADDR(sdl), lladdr_len) == 0 &&
 913                        lladdr_len == sdl->sdl_alen)
 914                        break;
 915        }
 916        return 0;
 917}
 918
 919static errno_t
 920ifnet_set_lladdr_internal(
 921        ifnet_t interface,
 922        const void *lladdr,
 923        size_t lladdr_len,
 924        u_char new_type,
 925        int apply_type)
 926{
 927        struct ifaddr *ifa;
 928        struct sockaddr_dl      *sdl;
 929        errno_t error = 0;
 930        
 931        if (interface == NULL) return EINVAL;
 932        
 933        if (lladdr_len != 0 && (lladdr_len != interface->if_addrlen || lladdr == 0))
 934                return EINVAL;
 935        
 936        ifnet_head_lock_shared();
 937        ifa = ifnet_addrs[interface->if_index - 1];
 938        if (ifa != NULL) {
 939                sdl = (struct sockaddr_dl*)ifa->ifa_addr;
 940                if (lladdr_len != 0) {
 941                        bcopy(lladdr, LLADDR(sdl), lladdr_len);
 942                }
 943                else {
 944                        bzero(LLADDR(sdl), interface->if_addrlen);
 945                }
 946                sdl->sdl_alen = lladdr_len;
 947                
 948                if (apply_type) {
 949                        sdl->sdl_type = new_type;
 950                }
 951        }
 952        else {
 953                error = ENXIO;
 954        }
 955        ifnet_head_done();
 956        
 957        /* Generate a kernel event */
 958        if (error == 0) {
 959                dlil_post_msg(interface, KEV_DL_SUBCLASS,
 960                        KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
 961        }
 962        
 963        return error;
 964}
 965
 966errno_t
 967ifnet_set_lladdr(
 968        ifnet_t interface,
 969        const void* lladdr,
 970        size_t lladdr_len)
 971{
 972        return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
 973}
 974
 975errno_t
 976ifnet_set_lladdr_and_type(
 977        ifnet_t interface,
 978        const void* lladdr,
 979        size_t lladdr_len,
 980        u_char type)
 981{
 982        return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1);
 983}
 984
 985errno_t
 986ifnet_add_multicast(
 987        ifnet_t interface,
 988        const struct sockaddr *maddr,
 989        ifmultiaddr_t *address)
 990{
 991        if (interface == NULL || maddr == NULL) return EINVAL;
 992        return if_addmulti(interface, maddr, address);
 993}
 994
 995errno_t
 996ifnet_remove_multicast(
 997        ifmultiaddr_t address)
 998{
 999        if (address == NULL) return EINVAL;
1000        return if_delmultiaddr(address, 0);
1001}
1002
1003errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses)
1004{
1005        int count = 0;
1006        int cmax = 0;
1007        struct ifmultiaddr *addr;
1008        int lock;
1009        
1010        if (interface == NULL || addresses == NULL)
1011                return EINVAL;
1012        
1013        lock = (interface->if_lock != 0);
1014        if (lock) ifnet_lock_shared(interface);
1015        if ((interface->if_eflags & IFEF_DETACHING) == 0) {
1016                LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1017                {
1018                        cmax++;
1019                }
1020        }
1021        else {
1022                if (lock) ifnet_lock_done(interface);
1023                return ENXIO;
1024        }
1025        
1026        MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
1027        if (*addresses == NULL) return ENOMEM;
1028        
1029        LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1030        {
1031                if (count + 1 > cmax)
1032                        break;
1033                (*addresses)[count] = (ifmultiaddr_t)addr;
1034                ifmaddr_reference((*addresses)[count]);
1035                count++;
1036        }
1037        (*addresses)[cmax] = 0;
1038        if (lock) ifnet_lock_done(interface);
1039        
1040        return 0;
1041}
1042
1043void
1044ifnet_free_multicast_list(
1045        ifmultiaddr_t *addresses)
1046{
1047        int i;
1048        
1049        if (addresses == NULL) return;
1050        
1051        for (i = 0; addresses[i] != NULL; i++)
1052        {
1053                ifmaddr_release(addresses[i]);
1054        }
1055        
1056        FREE(addresses, M_TEMP);
1057}
1058
1059errno_t
1060ifnet_find_by_name(
1061        const char *ifname,
1062        ifnet_t *interface)
1063{
1064        struct ifnet *ifp;
1065        int     namelen;
1066        
1067        if (ifname == NULL) return EINVAL;
1068        
1069        namelen = strlen(ifname);
1070        
1071        *interface = NULL;
1072        
1073        ifnet_head_lock_shared();
1074        TAILQ_FOREACH(ifp, &ifnet, if_link)
1075        {
1076                struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
1077                struct sockaddr_dl *ll_addr;
1078                
1079                if (!ifa || !ifa->ifa_addr)
1080                        continue;
1081                
1082                ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
1083                
1084                if ((ifp->if_eflags & IFEF_DETACHING) == 0 &&
1085                        namelen == ll_addr->sdl_nlen &&
1086                        (strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0))
1087                {
1088                        break;
1089                }
1090        }
1091        if (ifp) {
1092                *interface = ifp;
1093                ifnet_reference(*interface);
1094        }
1095        ifnet_head_done();
1096        
1097        return (ifp == NULL) ? ENXIO : 0;
1098}
1099
1100errno_t
1101ifnet_list_get(
1102        ifnet_family_t family,
1103        ifnet_t **list,
1104        u_int32_t *count)
1105{
1106        struct ifnet *ifp;
1107        u_int32_t cmax = 0;
1108        *count = 0;
1109        errno_t result = 0;
1110        
1111        if (list == NULL || count == NULL) return EINVAL;
1112        
1113        ifnet_head_lock_shared();
1114        TAILQ_FOREACH(ifp, &ifnet, if_link)
1115        {
1116                if (ifp->if_eflags & IFEF_DETACHING) continue;
1117                if (family == 0 || ifp->if_family == family)
1118                        cmax++;
1119        }
1120        
1121        if (cmax == 0)
1122                result = ENXIO;
1123        
1124        if (result == 0) {
1125                MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1), M_TEMP, M_NOWAIT);
1126                if (*list == NULL)
1127                        result = ENOMEM;
1128        }
1129
1130        if (result == 0) {
1131                TAILQ_FOREACH(ifp, &ifnet, if_link)
1132                {
1133                        if (ifp->if_eflags & IFEF_DETACHING) continue;
1134                        if (*count + 1 > cmax) break;
1135                        if (family == 0 || ((ifnet_family_t)ifp->if_family) == family)
1136                        {
1137                                (*list)[*count] = (ifnet_t)ifp;
1138                                ifnet_reference((*list)[*count]);
1139                                (*count)++;
1140                        }
1141                }
1142                (*list)[*count] = NULL;
1143        }
1144        ifnet_head_done();
1145        
1146        return 0;
1147}
1148
1149void
1150ifnet_list_free(
1151        ifnet_t *interfaces)
1152{
1153        int i;
1154        
1155        if (interfaces == NULL) return;
1156        
1157        for (i = 0; interfaces[i]; i++)
1158        {
1159                ifnet_release(interfaces[i]);
1160        }
1161        
1162        FREE(interfaces, M_TEMP);
1163}
1164
1165/****************************************************************************/
1166/* ifaddr_t accessors                                                                                                           */
1167/****************************************************************************/
1168
1169errno_t
1170ifaddr_reference(
1171        ifaddr_t ifa)
1172{
1173        if (ifa == NULL) return EINVAL;
1174        ifaref(ifa);
1175        return 0;
1176}
1177
1178errno_t
1179ifaddr_release(
1180        ifaddr_t ifa)
1181{
1182        if (ifa == NULL) return EINVAL;
1183        ifafree(ifa);
1184        return 0;
1185}
1186
1187sa_family_t
1188ifaddr_address_family(
1189        ifaddr_t ifa)
1190{
1191        if (ifa && ifa->ifa_addr)
1192                return ifa->ifa_addr->sa_family;
1193        
1194        return 0;
1195}
1196
1197errno_t
1198ifaddr_address(
1199        ifaddr_t ifa,
1200        struct sockaddr *out_addr,
1201        u_int32_t addr_size)
1202{
1203        u_int32_t copylen;
1204        
1205        if (ifa == NULL || out_addr == NULL) return EINVAL;
1206        if (ifa->ifa_addr == NULL) return ENOTSUP;
1207        
1208        copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size;
1209        bcopy(ifa->ifa_addr, out_addr, copylen);
1210        
1211        if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE;
1212        
1213        return 0;
1214}
1215
1216errno_t
1217ifaddr_dstaddress(
1218        ifaddr_t ifa,
1219        struct sockaddr *out_addr,
1220        u_int32_t addr_size)
1221{
1222        u_int32_t copylen;
1223        if (ifa == NULL || out_addr == NULL) return EINVAL;
1224        if (ifa->ifa_dstaddr == NULL) return ENOTSUP;
1225        
1226        copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size;
1227        bcopy(ifa->ifa_dstaddr, out_addr, copylen);
1228
1229        if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE;
1230        
1231        return 0;
1232}
1233
1234errno_t
1235ifaddr_netmask(
1236        ifaddr_t ifa,
1237        struct sockaddr *out_addr,
1238        u_int32_t addr_size)
1239{
1240        u_int32_t copylen;
1241        if (ifa == NULL || out_addr == NULL) return EINVAL;
1242        if (ifa->ifa_netmask == NULL) return ENOTSUP;
1243        
1244        copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size;
1245        bcopy(ifa->ifa_netmask, out_addr, copylen);
1246        
1247        if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE;
1248        
1249        return 0;
1250}
1251
1252ifnet_t
1253ifaddr_ifnet(
1254        ifaddr_t ifa)
1255{
1256        struct ifnet *ifp;
1257        if (ifa == NULL) return NULL;
1258        ifp = ifa->ifa_ifp;
1259        
1260        return (ifnet_t)ifp;
1261}
1262
1263ifaddr_t
1264ifaddr_withaddr(
1265        const struct sockaddr* address)
1266{
1267        if (address == NULL) return NULL;
1268        return ifa_ifwithaddr(address);
1269}
1270
1271ifaddr_t
1272ifaddr_withdstaddr(
1273        const struct sockaddr* address)
1274{
1275        if (address == NULL) return NULL;
1276        return ifa_ifwithdstaddr(address);
1277}
1278
1279ifaddr_t
1280ifaddr_withnet(
1281        const struct sockaddr* net)
1282{
1283        if (net == NULL) return NULL;
1284        return ifa_ifwithnet(net);
1285}
1286
1287ifaddr_t
1288ifaddr_withroute(
1289        int flags,
1290        const struct sockaddr* destination,
1291        const struct sockaddr* gateway)
1292{
1293        if (destination == NULL || gateway == NULL) return NULL;
1294        return ifa_ifwithroute(flags, destination, gateway);
1295}
1296
1297ifaddr_t
1298ifaddr_findbestforaddr(
1299        const struct sockaddr *addr,
1300        ifnet_t interface)
1301{
1302        if (addr == NULL || interface == NULL) return NULL;
1303        return ifaof_ifpforaddr(addr, interface);
1304}
1305
1306errno_t
1307ifmaddr_reference(
1308        ifmultiaddr_t ifmaddr)
1309{
1310        if (ifmaddr == NULL) return EINVAL;
1311        ifma_reference(ifmaddr);
1312        return 0;
1313}
1314
1315errno_t
1316ifmaddr_release(
1317        ifmultiaddr_t ifmaddr)
1318{
1319        if (ifmaddr == NULL) return EINVAL;
1320        ifma_release(ifmaddr);  
1321        return 0;
1322}
1323
1324errno_t
1325ifmaddr_address(
1326        ifmultiaddr_t ifmaddr,
1327        struct sockaddr *out_addr,
1328        u_int32_t addr_size)
1329{
1330        u_int32_t copylen;
1331        
1332        if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1333        if (ifmaddr->ifma_addr == NULL) return ENOTSUP;
1334        
1335        copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size;
1336        bcopy(ifmaddr->ifma_addr, out_addr, copylen);
1337        
1338        if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE;
1339        
1340        return 0;
1341}
1342
1343errno_t
1344ifmaddr_lladdress(
1345        ifmultiaddr_t ifmaddr,
1346        struct sockaddr *out_addr,
1347        u_int32_t addr_size)
1348{
1349        if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1350        if (ifmaddr->ifma_ll == NULL) return ENOTSUP;
1351        
1352        return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size);
1353}
1354
1355ifnet_t
1356ifmaddr_ifnet(
1357        ifmultiaddr_t ifmaddr)
1358{
1359        if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
1360        return ifmaddr->ifma_ifp;
1361}
1362
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.