1/* $NetBSD: af_inetany.c,v 1.14 2011/05/24 11:38:56 joerg Exp $ */ 2 3/*- 4 * Copyright (c) 2008 David Young. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29#ifndef lint 30__RCSID("$NetBSD: af_inetany.c,v 1.14 2011/05/24 11:38:56 joerg Exp $"); 31#endif /* not lint */ 32 33#include <sys/param.h> 34#include <sys/ioctl.h> 35#include <sys/socket.h> 36 37#include <net/if.h> 38#include <netinet/in.h> 39#include <netinet/in_var.h> 40#include <netinet6/nd6.h> 41 42#include <arpa/inet.h> 43 44#include <assert.h> 45#include <err.h> 46#include <errno.h> 47#include <ifaddrs.h> 48#include <netdb.h> 49#include <string.h> 50#include <stdlib.h> 51#include <stdio.h> 52#include <util.h> 53 54#include "env.h" 55#include "extern.h" 56#include "af_inetany.h" 57#include "prog_ops.h" 58 59static void * 60loadbuf(const struct apbuf *b, const struct paddr_prefix *pfx) 61{ 62 return memcpy(b->buf, &pfx->pfx_addr, 63 MIN(b->buflen, pfx->pfx_addr.sa_len)); 64} 65 66void 67commit_address(prop_dictionary_t env, prop_dictionary_t oenv, 68 const struct afparam *param) 69{ 70 const char *ifname; 71 int af, rc, s; 72 bool alias, delete, replace; 73 prop_data_t d; 74 const struct paddr_prefix *addr, *brd, *dst, *mask; 75 unsigned short flags; 76 77 if ((af = getaf(env)) == -1) 78 af = AF_INET; 79 80 if ((s = getsock(af)) == -1) 81 err(EXIT_FAILURE, "%s: getsock", __func__); 82 83 if ((ifname = getifname(env)) == NULL) 84 return; 85 86 strlcpy(param->name[0].buf, ifname, param->name[0].buflen); 87 strlcpy(param->name[1].buf, ifname, param->name[1].buflen); 88 89 if ((d = (prop_data_t)prop_dictionary_get(env, "address")) != NULL) 90 addr = prop_data_data_nocopy(d); 91 else if (!prop_dictionary_get_bool(env, "alias", &alias) || alias || 92 param->gifaddr.cmd == 0) 93 return; 94 else if (prog_ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == -1) 95 err(EXIT_FAILURE, "%s", param->gifaddr.desc); 96 else if (prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1) 97 err(EXIT_FAILURE, "%s", param->difaddr.desc); 98 else 99 return; 100 101 if ((d = (prop_data_t)prop_dictionary_get(env, "dst")) != NULL) 102 dst = prop_data_data_nocopy(d); 103 else 104 dst = NULL; 105 106 if ((d = (prop_data_t)prop_dictionary_get(env, "netmask")) != NULL) 107 mask = prop_data_data_nocopy(d); 108 else 109 mask = NULL; 110 111 if ((d = (prop_data_t)prop_dictionary_get(env, "broadcast")) != NULL) 112 brd = prop_data_data_nocopy(d); 113 else 114 brd = NULL; 115 116 if (!prop_dictionary_get_bool(env, "alias", &alias)) { 117 delete = false; 118 replace = (param->gifaddr.cmd != 0); 119 } else { 120 replace = false; 121 delete = !alias; 122 } 123 124 loadbuf(¶m->addr, addr); 125 126 /* TBD: read matching ifaddr from kernel, use the netmask as default 127 * TBD: handle preference 128 */ 129 if (getifflags(env, oenv, &flags) == -1) 130 err(EXIT_FAILURE, "%s: getifflags", __func__); 131 132 switch (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) { 133 case IFF_BROADCAST: 134 if (brd != NULL) 135 loadbuf(¶m->brd, brd); 136 /*FALLTHROUGH*/ 137 case 0: 138 break; 139 case IFF_POINTOPOINT: 140 if (brd != NULL) { 141 errx(EXIT_FAILURE, "%s is not a broadcast interface", 142 ifname); 143 } 144 if (dst != NULL) 145 loadbuf(¶m->dst, dst); 146 break; 147 case IFF_BROADCAST|IFF_POINTOPOINT: 148 errx(EXIT_FAILURE, "unsupported interface flags"); 149 } 150 if (param->mask.buf == NULL) { 151 if (mask != NULL) 152 errx(EXIT_FAILURE, "netmask not supported"); 153 } else if (mask != NULL) 154 loadbuf(¶m->mask, mask); 155 else if (param->defmask.buf != NULL) { 156 memcpy(param->mask.buf, param->defmask.buf, 157 MIN(param->mask.buflen, param->defmask.buflen)); 158 } 159 if (replace) { 160 if (prog_ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == 0) { 161 rc = prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf); 162 if (rc == -1) 163 err(EXIT_FAILURE, "%s", param->difaddr.desc); 164 } else if (errno == EADDRNOTAVAIL) 165 ; /* No address was assigned yet. */ 166 else 167 err(EXIT_FAILURE, "%s", param->gifaddr.desc); 168 } else if (delete) { 169 loadbuf(¶m->dgaddr, addr); 170 if (prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1) 171 err(EXIT_FAILURE, "%s", param->difaddr.desc); 172 return; 173 } 174 if (param->pre_aifaddr != NULL && 175 (*param->pre_aifaddr)(env, param) == -1) 176 err(EXIT_FAILURE, "pre-%s", param->aifaddr.desc); 177 if (prog_ioctl(s, param->aifaddr.cmd, param->req.buf) == -1) 178 err(EXIT_FAILURE, "%s", param->aifaddr.desc); 179} 180