1/** 2 * \file 3 * \brief Port allocator for netd 4 * 5 * This file is part of the net "daemon" 6 */ 7 8/* 9 * Copyright (c) 2007, 2008, 2009, 2010 ETH Zurich. 10 * All rights reserved. 11 * 12 * This file is distributed under the terms in the attached LICENSE file. 13 * If you do not find this file, copies can be found by writing to: 14 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: NetOS Group. 15 */ 16 17#include <assert.h> 18#include <stdlib.h> 19#include <stdio.h> 20#include <barrelfish/barrelfish.h> 21#include <if/net_ports_defs.h> 22#include "portalloc.h" 23#include "device_manager_debug.h" 24 25/** 26 * The arrays storing the current port allocation state 27 */ 28static uint64_t free_tcp_ports[TCP_ARRAY_SIZE]; 29static uint64_t free_udp_ports[UDP_ARRAY_SIZE]; 30 31 32/** 33 * @brief Initialization code for port allocator 34 */ 35void init_free_ports(void) 36{ 37 uint64_t i; 38 39 for (i = 0; i < TCP_ARRAY_SIZE; i++) { 40 free_tcp_ports[i] = M64; 41 } 42 for (i = 0; i < UDP_ARRAY_SIZE; i++) { 43 free_udp_ports[i] = M64; 44 } 45} 46 47 48/** 49 * @brief Allocates the first free port found starting from pstart 50 * @param free_ports the array of port allocation data 51 * @param type UDP or TCP 52 * @param pstart defines the port it starts searching from 53 * 54 * @return the proposed port number or 0 in case all ports are allocated 55 */ 56static uint16_t alloc_port(uint64_t * free_ports, net_ports_port_type_t type, 57 uint16_t pstart) 58{ 59 //k: asq did this to be generic? 60 //uint32_t v32; 61 //uint16_t v16; 62 //uint8_t v8; 63 int bitnr = 0; 64 uint64_t m = M32, v; 65 int s = 32; 66 uint64_t len; 67 uint64_t start; 68 69 if (type == net_ports_PORT_TCP) { 70 len = TCP_ARRAY_SIZE; 71 start = TCP_LOCAL_PORT_RANGE_START / 64; 72 } else { 73 len = UDP_ARRAY_SIZE; 74 start = UDP_LOCAL_PORT_RANGE_START / 64; 75 } 76 77 for (int i = start; i < len; i++) { 78 //find a 64bit word which has at least 1 bit set (=1 free port) 79 if (free_ports[i]) { 80 v = free_ports[i]; 81 //binary search the 1-bit 82 while (m > 0) { 83 if (v & m) { 84 v = v & m; 85 } else { 86 v = (v >> s) & m; 87 bitnr += s; 88 } 89 if (s != 1) { 90 s /= 2; 91 } 92 m >>= s; 93 } 94 //bitnr is now the bitposition within the current 64 bit word which 95 //will be the allocated portnummer 96 assert(bitnr >= 0 && bitnr <= 63); 97 //mark the port as allocated 98 free_ports[i] &= ~(1 << bitnr); 99 //return the port number 100 101 return (bitnr + i * sizeof(uint64_t) * 8 + pstart); 102 } 103 } 104 return (0); //no port could be allocated 105} 106 107/** 108 * @brief allocates a tcp port 109 * 110 */ 111uint16_t alloc_tcp_port(void) 112{ 113 return alloc_port(free_tcp_ports, net_ports_PORT_TCP, 114 TCP_LOCAL_PORT_RANGE_START); 115} 116 117/** 118 * @brief allocates a tcp port 119 * 120 */ 121uint16_t alloc_udp_port(void) 122{ 123 return alloc_port(free_udp_ports, net_ports_PORT_UDP, 124 UDP_LOCAL_PORT_RANGE_START); 125} 126 127/** 128 * @brief checks to see whether a given port is free for use 129 * 130 * @param free_ports the array of either tcp or udp allocation state 131 * @param port the port number to be checked 132 * 133 * @return true in case the port is free and otherwise false 134 */ 135static inline bool check_free(uint64_t * free_ports, uint16_t port) 136{ 137 uint16_t pidx = port; 138 139 return (free_ports[pidx / 64] & (1 << (pidx % 64))); 140} 141 142/** 143 * @brief allocates a specific port. this is the backend function for bind 144 * 145 * @param port the port number 146 * @param type UDP or TCP 147 * 148 * @return 0 in case port is in use and the port number other wise 149 */ 150inline uint16_t alloc_specific_port(uint16_t port, net_ports_port_type_t type) 151{ 152 uint16_t pidx = port; 153 uint64_t *free_ports; 154 155 NDM_DEBUG("allocating port %u with type %d\n", port, type); 156 if (type == net_ports_PORT_TCP) { 157 free_ports = free_tcp_ports; 158 } else { 159 free_ports = free_udp_ports; 160 } 161 if (free_ports[pidx / 64] & (1 << (pidx % 64))) { 162 free_ports[pidx / 64] &= ~(1 << (pidx % 64)); 163 return port; 164 } else { 165 return (0); 166 } 167} 168 169/** 170 * @brief frees a port and does not care whether it is allocated before or not! 171 * 172 * @param port the port number 173 * @param type UDP or TCP 174 */ 175inline void free_port(uint16_t port, net_ports_port_type_t type) 176{ 177 uint64_t *free_ports = 178 (type == net_ports_PORT_TCP) ? free_tcp_ports : free_udp_ports; 179 free_ports[port / 64] |= (1 << (port % 64)); 180} 181