util.c revision 1.2
1/* $OpenBSD: util.c,v 1.2 2012/10/22 07:28:49 bluhm Exp $ */ 2 3/* 4 * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <netinet/in.h> 22#include <string.h> 23 24#include "ospf6d.h" 25#include "log.h" 26 27#define IN6_IS_SCOPE_EMBED(a) \ 28 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 29 (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \ 30 (IN6_IS_ADDR_MC_INTFACELOCAL(a))) 31 32void 33embedscope(struct sockaddr_in6 *sin6) 34{ 35 u_int16_t tmp16; 36 37 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 38 bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 39 if (tmp16 != 0) { 40 log_warnx("embedscope: address %s already has embeded " 41 "scope %u", log_sockaddr(sin6), ntohs(tmp16)); 42 } 43 tmp16 = htons(sin6->sin6_scope_id); 44 bcopy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 45 sin6->sin6_scope_id = 0; 46 } 47} 48 49void 50recoverscope(struct sockaddr_in6 *sin6) 51{ 52 u_int16_t tmp16; 53 54 if (sin6->sin6_scope_id != 0) { 55 log_warnx("recoverscope: address %s already has scope id %u", 56 log_sockaddr(sin6), sin6->sin6_scope_id); 57 } 58 59 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 60 bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 61 sin6->sin6_scope_id = ntohs(tmp16); 62 sin6->sin6_addr.s6_addr[2] = 0; 63 sin6->sin6_addr.s6_addr[3] = 0; 64 } 65} 66 67void 68addscope(struct sockaddr_in6 *sin6, u_int32_t id) 69{ 70 if (sin6->sin6_scope_id != 0) { 71 log_warnx("addscope: address %s already has scope id %u", 72 log_sockaddr(sin6), sin6->sin6_scope_id); 73 } 74 75 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 76 sin6->sin6_scope_id = id; 77 } 78} 79 80void 81clearscope(struct in6_addr *in6) 82{ 83 if (IN6_IS_SCOPE_EMBED(in6)) { 84 in6->s6_addr[2] = 0; 85 in6->s6_addr[3] = 0; 86 } 87} 88 89#undef IN6_IS_SCOPE_EMBED 90 91u_int8_t 92mask2prefixlen(struct sockaddr_in6 *sa_in6) 93{ 94 u_int8_t l = 0, *ap, *ep; 95 96 /* 97 * sin6_len is the size of the sockaddr so substract the offset of 98 * the possibly truncated sin6_addr struct. 99 */ 100 ap = (u_int8_t *)&sa_in6->sin6_addr; 101 ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; 102 for (; ap < ep; ap++) { 103 /* this "beauty" is adopted from sbin/route/show.c ... */ 104 switch (*ap) { 105 case 0xff: 106 l += 8; 107 break; 108 case 0xfe: 109 l += 7; 110 return (l); 111 case 0xfc: 112 l += 6; 113 return (l); 114 case 0xf8: 115 l += 5; 116 return (l); 117 case 0xf0: 118 l += 4; 119 return (l); 120 case 0xe0: 121 l += 3; 122 return (l); 123 case 0xc0: 124 l += 2; 125 return (l); 126 case 0x80: 127 l += 1; 128 return (l); 129 case 0x00: 130 return (l); 131 default: 132 fatalx("non contiguous inet6 netmask"); 133 } 134 } 135 136 return (l); 137} 138 139struct in6_addr * 140prefixlen2mask(u_int8_t prefixlen) 141{ 142 static struct in6_addr mask; 143 int i; 144 145 bzero(&mask, sizeof(mask)); 146 for (i = 0; i < prefixlen / 8; i++) 147 mask.s6_addr[i] = 0xff; 148 i = prefixlen % 8; 149 if (i) 150 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 151 152 return (&mask); 153} 154 155void 156inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 157{ 158 struct in6_addr mask; 159 int i; 160 161 bzero(&mask, sizeof(mask)); 162 for (i = 0; i < prefixlen / 8; i++) 163 mask.s6_addr[i] = 0xff; 164 i = prefixlen % 8; 165 if (i) 166 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 167 168 for (i = 0; i < 16; i++) 169 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 170} 171