util.c revision 1.1
1/* $OpenBSD: util.c,v 1.1 2012/10/21 21:30:44 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 68clearscope(struct in6_addr *in6) 69{ 70 if (IN6_IS_SCOPE_EMBED(in6)) { 71 in6->s6_addr[2] = 0; 72 in6->s6_addr[3] = 0; 73 } 74} 75 76#undef IN6_IS_SCOPE_EMBED 77 78u_int8_t 79mask2prefixlen(struct sockaddr_in6 *sa_in6) 80{ 81 u_int8_t l = 0, *ap, *ep; 82 83 /* 84 * sin6_len is the size of the sockaddr so substract the offset of 85 * the possibly truncated sin6_addr struct. 86 */ 87 ap = (u_int8_t *)&sa_in6->sin6_addr; 88 ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; 89 for (; ap < ep; ap++) { 90 /* this "beauty" is adopted from sbin/route/show.c ... */ 91 switch (*ap) { 92 case 0xff: 93 l += 8; 94 break; 95 case 0xfe: 96 l += 7; 97 return (l); 98 case 0xfc: 99 l += 6; 100 return (l); 101 case 0xf8: 102 l += 5; 103 return (l); 104 case 0xf0: 105 l += 4; 106 return (l); 107 case 0xe0: 108 l += 3; 109 return (l); 110 case 0xc0: 111 l += 2; 112 return (l); 113 case 0x80: 114 l += 1; 115 return (l); 116 case 0x00: 117 return (l); 118 default: 119 fatalx("non contiguous inet6 netmask"); 120 } 121 } 122 123 return (l); 124} 125 126struct in6_addr * 127prefixlen2mask(u_int8_t prefixlen) 128{ 129 static struct in6_addr mask; 130 int i; 131 132 bzero(&mask, sizeof(mask)); 133 for (i = 0; i < prefixlen / 8; i++) 134 mask.s6_addr[i] = 0xff; 135 i = prefixlen % 8; 136 if (i) 137 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 138 139 return (&mask); 140} 141 142void 143inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 144{ 145 struct in6_addr mask; 146 int i; 147 148 bzero(&mask, sizeof(mask)); 149 for (i = 0; i < prefixlen / 8; i++) 150 mask.s6_addr[i] = 0xff; 151 i = prefixlen % 8; 152 if (i) 153 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 154 155 for (i = 0; i < 16; i++) 156 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 157} 158