darwin-xnu/bsd/net/multicast_list.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/*
  24 * multicast_util.c:
  25 * - keep track of multicast addresses added to one interface based on the
  26 *   actual multicast addresses in another
  27 * - used by VLAN and BOND
  28 */
  29
  30/*
  31 * Modification History:
  32 *
  33 * April 29, 2004       Dieter Siegmund (dieter@apple.com)
  34 * - created
  35 */
  36
  37#include <net/multicast_list.h>
  38#include <sys/param.h>
  39#include <sys/systm.h>
  40#include <sys/malloc.h>
  41#include <net/if_dl.h>
  42
  43__private_extern__ void
  44multicast_list_init(struct multicast_list * mc_list)
  45{
  46    SLIST_INIT(mc_list);
  47    return;
  48}
  49
  50/*
  51 * Function: multicast_list_remove
  52 * Purpose:
  53 *   Remove the given list of multicast addresses from the interface and from
  54 *   the multicast list structure.
  55 */
  56__private_extern__ int
  57multicast_list_remove(struct multicast_list * mc_list)
  58{
  59    int                         error;
  60    struct multicast_entry *    mc;
  61    int                         result = 0;
  62
  63    while ((mc = SLIST_FIRST(mc_list)) != NULL) {
  64        error = ifnet_remove_multicast(mc->mc_ifma);
  65        if (error != 0) {
  66            result = error;
  67        }
  68        SLIST_REMOVE_HEAD(mc_list, mc_entries);
  69        ifmaddr_release(mc->mc_ifma);
  70        FREE(mc, M_DEVBUF);
  71    }
  72    return (result);
  73}
  74
  75/*
  76 * Function: multicast_list_program
  77 * Purpose:
  78 *   Program the multicast filter on "target_ifp" using the values from
  79 *   "source_ifp", and saving the result in "mc_list"
  80 *
  81 *   We build a new list of multicast addresses while programming the new list.
  82 *   If that completes successfully, we remove the old list, and return the 
  83 *   new list.
  84 *
  85 *   If it fails, we remove what we've added to the new list, and
  86 *   return an error.
  87 */
  88__private_extern__ int
  89multicast_list_program(struct multicast_list * mc_list,
  90                       struct ifnet * source_ifp,
  91                       struct ifnet * target_ifp)
  92{
  93    int                         alen;
  94    int                         error = 0;
  95    int                         i;
  96    struct multicast_entry *    mc = NULL;
  97    struct multicast_list       new_mc_list;
  98    struct sockaddr_dl          source_sdl;
  99    ifmultiaddr_t *             source_multicast_list;
 100    struct sockaddr_dl          target_sdl;
 101
 102    alen = target_ifp->if_addrlen;
 103    bzero((char *)&target_sdl, sizeof(target_sdl));
 104    target_sdl.sdl_len = sizeof(target_sdl);
 105    target_sdl.sdl_family = AF_LINK;
 106    target_sdl.sdl_type = target_ifp->if_type;
 107    target_sdl.sdl_alen = alen;
 108    target_sdl.sdl_index = target_ifp->if_index;
 109
 110    /* build a new list */
 111    multicast_list_init(&new_mc_list);
 112    error = ifnet_get_multicast_list(source_ifp, &source_multicast_list);
 113    if (error != 0) {
 114        printf("multicast_list_program: "
 115               "ifnet_get_multicast_list(%s%d) failed, %d\n",
 116               source_ifp->if_name, source_ifp->if_unit, error);
 117        return (error);
 118    }
 119    for (i = 0; source_multicast_list[i] != NULL; i++) {
 120        if (ifmaddr_address(source_multicast_list[i], 
 121                            (struct sockaddr *)&source_sdl, 
 122                            sizeof(source_sdl)) != 0
 123            || source_sdl.sdl_family != AF_LINK) {
 124            continue;
 125        }
 126        mc = _MALLOC(sizeof(struct multicast_entry), M_DEVBUF, M_WAITOK);
 127        bcopy(LLADDR(&source_sdl), LLADDR(&target_sdl), alen);
 128        error = ifnet_add_multicast(target_ifp, (struct sockaddr *)&target_sdl, 
 129                                    &mc->mc_ifma);
 130        if (error != 0) {
 131            FREE(mc, M_DEVBUF);
 132            break;
 133        }
 134        SLIST_INSERT_HEAD(&new_mc_list, mc, mc_entries);
 135    }
 136    if (error != 0) {
 137        /* restore previous state */
 138        (void)multicast_list_remove(&new_mc_list);
 139    } else {
 140        /* remove the old entries, and return the new list */
 141        (void)multicast_list_remove(mc_list);
 142        *mc_list = new_mc_list;
 143    }
 144    return (error);
 145}
 146
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.