1/* $NetBSD: portset.c,v 1.6 2022/09/23 12:15:33 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <inttypes.h> 19#include <stdbool.h> 20 21#include <isc/mem.h> 22#include <isc/portset.h> 23#include <isc/string.h> 24#include <isc/types.h> 25#include <isc/util.h> 26 27#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(uint32_t) * 8)) 28 29/*% 30 * Internal representation of portset. It's an array of 32-bit integers, each 31 * bit corresponding to a single port in the ascending order. For example, 32 * the second most significant bit of buf[0] corresponds to port 1. 33 */ 34struct isc_portset { 35 unsigned int nports; /*%< number of ports in the set */ 36 uint32_t buf[ISC_PORTSET_BUFSIZE]; 37}; 38 39static bool 40portset_isset(isc_portset_t *portset, in_port_t port) { 41 return ((portset->buf[port >> 5] & ((uint32_t)1 << (port & 31))) != 0); 42} 43 44static void 45portset_add(isc_portset_t *portset, in_port_t port) { 46 if (!portset_isset(portset, port)) { 47 portset->nports++; 48 portset->buf[port >> 5] |= ((uint32_t)1 << (port & 31)); 49 } 50} 51 52static void 53portset_remove(isc_portset_t *portset, in_port_t port) { 54 if (portset_isset(portset, port)) { 55 portset->nports--; 56 portset->buf[port >> 5] &= ~((uint32_t)1 << (port & 31)); 57 } 58} 59 60isc_result_t 61isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) { 62 isc_portset_t *portset; 63 64 REQUIRE(portsetp != NULL && *portsetp == NULL); 65 66 portset = isc_mem_get(mctx, sizeof(*portset)); 67 68 /* Make the set 'empty' by default */ 69 memset(portset, 0, sizeof(*portset)); 70 *portsetp = portset; 71 72 return (ISC_R_SUCCESS); 73} 74 75void 76isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) { 77 isc_portset_t *portset; 78 79 REQUIRE(portsetp != NULL); 80 portset = *portsetp; 81 82 isc_mem_put(mctx, portset, sizeof(*portset)); 83} 84 85bool 86isc_portset_isset(isc_portset_t *portset, in_port_t port) { 87 REQUIRE(portset != NULL); 88 89 return (portset_isset(portset, port)); 90} 91 92unsigned int 93isc_portset_nports(isc_portset_t *portset) { 94 REQUIRE(portset != NULL); 95 96 return (portset->nports); 97} 98 99void 100isc_portset_add(isc_portset_t *portset, in_port_t port) { 101 REQUIRE(portset != NULL); 102 103 portset_add(portset, port); 104} 105 106void 107isc_portset_remove(isc_portset_t *portset, in_port_t port) { 108 portset_remove(portset, port); 109} 110 111void 112isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo, 113 in_port_t port_hi) { 114 in_port_t p; 115 116 REQUIRE(portset != NULL); 117 REQUIRE(port_lo <= port_hi); 118 119 p = port_lo; 120 do { 121 portset_add(portset, p); 122 } while (p++ < port_hi); 123} 124 125void 126isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo, 127 in_port_t port_hi) { 128 in_port_t p; 129 130 REQUIRE(portset != NULL); 131 REQUIRE(port_lo <= port_hi); 132 133 p = port_lo; 134 do { 135 portset_remove(portset, p); 136 } while (p++ < port_hi); 137} 138