[c69d327] | 1 | /*
|
---|
| 2 | * Copyright (c) 2009 Lukas Mejdrech
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without
|
---|
| 6 | * modification, are permitted provided that the following conditions
|
---|
| 7 | * are met:
|
---|
| 8 | *
|
---|
| 9 | * - Redistributions of source code must retain the above copyright
|
---|
| 10 | * notice, this list of conditions and the following disclaimer.
|
---|
| 11 | * - 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 | * - The name of the author may not be used to endorse or promote products
|
---|
| 15 | * derived from this software without specific prior written permission.
|
---|
| 16 | *
|
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | /** @addtogroup libc
|
---|
| 30 | * @{
|
---|
| 31 | */
|
---|
| 32 |
|
---|
| 33 | /** @file
|
---|
| 34 | * Packet map and queue implementation.
|
---|
| 35 | * This file has to be compiled with both the packet server and the client.
|
---|
| 36 | */
|
---|
| 37 |
|
---|
| 38 | #include <malloc.h>
|
---|
| 39 | #include <mem.h>
|
---|
| 40 | #include <fibril_synch.h>
|
---|
| 41 | #include <unistd.h>
|
---|
| 42 | #include <errno.h>
|
---|
| 43 |
|
---|
| 44 | #include <sys/mman.h>
|
---|
| 45 |
|
---|
| 46 | #include <adt/generic_field.h>
|
---|
| 47 | #include <net/packet.h>
|
---|
| 48 | #include <net/packet_header.h>
|
---|
| 49 |
|
---|
| 50 | /** Packet map page size. */
|
---|
| 51 | #define PACKET_MAP_SIZE 100
|
---|
| 52 |
|
---|
| 53 | /** Returns the packet map page index.
|
---|
| 54 | * @param[in] packet_id The packet identifier.
|
---|
| 55 | */
|
---|
| 56 | #define PACKET_MAP_PAGE(packet_id) (((packet_id) - 1) / PACKET_MAP_SIZE)
|
---|
| 57 |
|
---|
| 58 | /** Returns the packet index in the corresponding packet map page.
|
---|
| 59 | * @param[in] packet_id The packet identifier.
|
---|
| 60 | */
|
---|
| 61 | #define PACKET_MAP_INDEX(packet_id) (((packet_id) - 1) % PACKET_MAP_SIZE)
|
---|
| 62 |
|
---|
| 63 | /** Type definition of the packet map page. */
|
---|
| 64 | typedef packet_t packet_map_t[PACKET_MAP_SIZE];
|
---|
| 65 |
|
---|
| 66 | /** Type definition of the packet map page pointer. */
|
---|
| 67 | typedef packet_map_t * packet_map_ref;
|
---|
| 68 |
|
---|
| 69 | /** Packet map.
|
---|
| 70 | * Maps packet identifiers to the packet references.
|
---|
| 71 | * @see generic_field.h
|
---|
| 72 | */
|
---|
| 73 | GENERIC_FIELD_DECLARE(gpm, packet_map_t);
|
---|
| 74 |
|
---|
| 75 | /** Packet map global data. */
|
---|
| 76 | static struct {
|
---|
| 77 | /** Safety lock. */
|
---|
| 78 | fibril_rwlock_t lock;
|
---|
| 79 | /** Packet map. */
|
---|
| 80 | gpm_t packet_map;
|
---|
| 81 | } pm_globals;
|
---|
| 82 |
|
---|
| 83 | GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
|
---|
| 84 |
|
---|
| 85 | /** Initializes the packet map.
|
---|
| 86 | *
|
---|
| 87 | * @returns EOK on success.
|
---|
| 88 | * @returns ENOMEM if there is not enough memory left.
|
---|
| 89 | */
|
---|
| 90 | int pm_init(void)
|
---|
| 91 | {
|
---|
[16ac756] | 92 | int rc;
|
---|
[c69d327] | 93 |
|
---|
| 94 | fibril_rwlock_initialize(&pm_globals.lock);
|
---|
[16ac756] | 95 |
|
---|
[c69d327] | 96 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
[16ac756] | 97 | rc = gpm_initialize(&pm_globals.packet_map);
|
---|
[c69d327] | 98 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
[16ac756] | 99 |
|
---|
| 100 | return rc;
|
---|
[c69d327] | 101 | }
|
---|
| 102 |
|
---|
| 103 | /** Finds the packet mapping.
|
---|
| 104 | *
|
---|
| 105 | * @param[in] packet_id The packet identifier to be found.
|
---|
| 106 | * @returns The found packet reference.
|
---|
| 107 | * @returns NULL if the mapping does not exist.
|
---|
| 108 | */
|
---|
| 109 | packet_t pm_find(packet_id_t packet_id)
|
---|
| 110 | {
|
---|
| 111 | packet_map_ref map;
|
---|
| 112 | packet_t packet;
|
---|
| 113 |
|
---|
| 114 | if (!packet_id)
|
---|
| 115 | return NULL;
|
---|
| 116 |
|
---|
| 117 | fibril_rwlock_read_lock(&pm_globals.lock);
|
---|
| 118 | if (packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)) {
|
---|
| 119 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 120 | return NULL;
|
---|
| 121 | }
|
---|
| 122 | map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
|
---|
| 123 | if (!map) {
|
---|
| 124 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 125 | return NULL;
|
---|
| 126 | }
|
---|
| 127 | packet = (*map) [PACKET_MAP_INDEX(packet_id)];
|
---|
| 128 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 129 | return packet;
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | /** Adds the packet mapping.
|
---|
| 133 | *
|
---|
| 134 | * @param[in] packet The packet to be remembered.
|
---|
| 135 | * @returns EOK on success.
|
---|
| 136 | * @returns EINVAL if the packet is not valid.
|
---|
| 137 | * @returns EINVAL if the packet map is not initialized.
|
---|
| 138 | * @returns ENOMEM if there is not enough memory left.
|
---|
| 139 | */
|
---|
| 140 | int pm_add(packet_t packet)
|
---|
| 141 | {
|
---|
| 142 | packet_map_ref map;
|
---|
[16ac756] | 143 | int rc;
|
---|
[c69d327] | 144 |
|
---|
| 145 | if (!packet_is_valid(packet))
|
---|
| 146 | return EINVAL;
|
---|
| 147 |
|
---|
| 148 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
| 149 |
|
---|
| 150 | if (PACKET_MAP_PAGE(packet->packet_id) <
|
---|
| 151 | gpm_count(&pm_globals.packet_map)) {
|
---|
| 152 | map = gpm_get_index(&pm_globals.packet_map,
|
---|
| 153 | PACKET_MAP_PAGE(packet->packet_id));
|
---|
| 154 | } else {
|
---|
| 155 | do {
|
---|
| 156 | map = (packet_map_ref) malloc(sizeof(packet_map_t));
|
---|
| 157 | if (!map) {
|
---|
| 158 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 159 | return ENOMEM;
|
---|
| 160 | }
|
---|
| 161 | bzero(map, sizeof(packet_map_t));
|
---|
[16ac756] | 162 | rc = gpm_add(&pm_globals.packet_map, map);
|
---|
| 163 | if (rc < 0) {
|
---|
[c69d327] | 164 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 165 | free(map);
|
---|
[16ac756] | 166 | return rc;
|
---|
[c69d327] | 167 | }
|
---|
| 168 | } while (PACKET_MAP_PAGE(packet->packet_id) >=
|
---|
| 169 | gpm_count(&pm_globals.packet_map));
|
---|
| 170 | }
|
---|
| 171 |
|
---|
| 172 | (*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
|
---|
| 173 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 174 | return EOK;
|
---|
| 175 | }
|
---|
| 176 |
|
---|
| 177 | /** Releases the packet map. */
|
---|
| 178 | void pm_destroy(void)
|
---|
| 179 | {
|
---|
| 180 | int count;
|
---|
| 181 | int index;
|
---|
| 182 | packet_map_ref map;
|
---|
| 183 | packet_t packet;
|
---|
| 184 |
|
---|
| 185 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
| 186 | count = gpm_count(&pm_globals.packet_map);
|
---|
| 187 | while (count > 0) {
|
---|
| 188 | map = gpm_get_index(&pm_globals.packet_map, count - 1);
|
---|
| 189 | for (index = PACKET_MAP_SIZE - 1; index >= 0; --index) {
|
---|
| 190 | packet = (*map)[index];
|
---|
| 191 | if (packet_is_valid(packet))
|
---|
| 192 | munmap(packet, packet->length);
|
---|
| 193 | }
|
---|
| 194 | }
|
---|
| 195 | gpm_destroy(&pm_globals.packet_map);
|
---|
| 196 | // leave locked
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | /** Add packet to the sorted queue.
|
---|
| 200 | *
|
---|
| 201 | * The queue is sorted in the ascending order.
|
---|
| 202 | * The packet is inserted right before the packets of the same order value.
|
---|
| 203 | *
|
---|
| 204 | * @param[in,out] first The first packet of the queue. Sets the first packet of
|
---|
| 205 | * the queue. The original first packet may be shifted by
|
---|
| 206 | * the new packet.
|
---|
| 207 | * @param[in] packet The packet to be added.
|
---|
| 208 | * @param[in] order The packet order value.
|
---|
| 209 | * @param[in] metric The metric value of the packet.
|
---|
| 210 | * @returns EOK on success.
|
---|
| 211 | * @returns EINVAL if the first parameter is NULL.
|
---|
| 212 | * @returns EINVAL if the packet is not valid.
|
---|
| 213 | */
|
---|
| 214 | int pq_add(packet_t * first, packet_t packet, size_t order, size_t metric)
|
---|
| 215 | {
|
---|
| 216 | packet_t item;
|
---|
| 217 |
|
---|
| 218 | if (!first || !packet_is_valid(packet))
|
---|
| 219 | return EINVAL;
|
---|
| 220 |
|
---|
| 221 | pq_set_order(packet, order, metric);
|
---|
| 222 | if (packet_is_valid(*first)) {
|
---|
| 223 | item = * first;
|
---|
| 224 | do {
|
---|
| 225 | if (item->order < order) {
|
---|
| 226 | if (item->next) {
|
---|
| 227 | item = pm_find(item->next);
|
---|
| 228 | } else {
|
---|
| 229 | item->next = packet->packet_id;
|
---|
| 230 | packet->previous = item->packet_id;
|
---|
| 231 | return EOK;
|
---|
| 232 | }
|
---|
| 233 | } else {
|
---|
| 234 | packet->previous = item->previous;
|
---|
| 235 | packet->next = item->packet_id;
|
---|
| 236 | item->previous = packet->packet_id;
|
---|
| 237 | item = pm_find(packet->previous);
|
---|
| 238 | if (item)
|
---|
| 239 | item->next = packet->packet_id;
|
---|
| 240 | else
|
---|
| 241 | *first = packet;
|
---|
| 242 | return EOK;
|
---|
| 243 | }
|
---|
| 244 | } while (packet_is_valid(item));
|
---|
| 245 | }
|
---|
| 246 | *first = packet;
|
---|
| 247 | return EOK;
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | /** Finds the packet with the given order.
|
---|
| 251 | *
|
---|
| 252 | * @param[in] first The first packet of the queue.
|
---|
| 253 | * @param[in] order The packet order value.
|
---|
| 254 | * @returns The packet with the given order.
|
---|
| 255 | * @returns NULL if the first packet is not valid.
|
---|
| 256 | * @returns NULL if the packet is not found.
|
---|
| 257 | */
|
---|
| 258 | packet_t pq_find(packet_t packet, size_t order)
|
---|
| 259 | {
|
---|
| 260 | packet_t item;
|
---|
| 261 |
|
---|
| 262 | if (!packet_is_valid(packet))
|
---|
| 263 | return NULL;
|
---|
| 264 |
|
---|
| 265 | item = packet;
|
---|
| 266 | do {
|
---|
| 267 | if (item->order == order)
|
---|
| 268 | return item;
|
---|
| 269 |
|
---|
| 270 | item = pm_find(item->next);
|
---|
| 271 | } while (item && (item != packet) && packet_is_valid(item));
|
---|
| 272 |
|
---|
| 273 | return NULL;
|
---|
| 274 | }
|
---|
| 275 |
|
---|
| 276 | /** Inserts packet after the given one.
|
---|
| 277 | *
|
---|
| 278 | * @param[in] packet The packet in the queue.
|
---|
| 279 | * @param[in] new_packet The new packet to be inserted.
|
---|
| 280 | * @returns EOK on success.
|
---|
| 281 | * @returns EINVAL if etiher of the packets is invalid.
|
---|
| 282 | */
|
---|
| 283 | int pq_insert_after(packet_t packet, packet_t new_packet)
|
---|
| 284 | {
|
---|
| 285 | packet_t item;
|
---|
| 286 |
|
---|
| 287 | if (!packet_is_valid(packet) || !packet_is_valid(new_packet))
|
---|
| 288 | return EINVAL;
|
---|
| 289 |
|
---|
| 290 | new_packet->previous = packet->packet_id;
|
---|
| 291 | new_packet->next = packet->next;
|
---|
| 292 | item = pm_find(packet->next);
|
---|
| 293 | if (item)
|
---|
| 294 | item->previous = new_packet->packet_id;
|
---|
| 295 | packet->next = new_packet->packet_id;
|
---|
| 296 |
|
---|
| 297 | return EOK;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | /** Detach the packet from the queue.
|
---|
| 301 | *
|
---|
| 302 | * @param[in] packet The packet to be detached.
|
---|
| 303 | * @returns The next packet in the queue. If the packet is the first
|
---|
| 304 | * one of the queue, this becomes the new first one.
|
---|
| 305 | * @returns NULL if there is no packet left.
|
---|
| 306 | * @returns NULL if the packet is not valid.
|
---|
| 307 | */
|
---|
| 308 | packet_t pq_detach(packet_t packet)
|
---|
| 309 | {
|
---|
| 310 | packet_t next;
|
---|
| 311 | packet_t previous;
|
---|
| 312 |
|
---|
| 313 | if (!packet_is_valid(packet))
|
---|
| 314 | return NULL;
|
---|
| 315 |
|
---|
| 316 | next = pm_find(packet->next);
|
---|
| 317 | if (next) {
|
---|
| 318 | next->previous = packet->previous;
|
---|
| 319 | previous = pm_find(next->previous);
|
---|
| 320 | if (previous)
|
---|
| 321 | previous->next = next->packet_id;
|
---|
| 322 | }
|
---|
| 323 | packet->previous = 0;
|
---|
| 324 | packet->next = 0;
|
---|
| 325 | return next;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /** Sets the packet order and metric attributes.
|
---|
| 329 | *
|
---|
| 330 | * @param[in] packeti The packet to be set.
|
---|
| 331 | * @param[in] order The packet order value.
|
---|
| 332 | * @param[in] metric The metric value of the packet.
|
---|
| 333 | * @returns EOK on success.
|
---|
| 334 | * @returns EINVAL if the packet is invalid.
|
---|
| 335 | */
|
---|
| 336 | int pq_set_order(packet_t packet, size_t order, size_t metric)
|
---|
| 337 | {
|
---|
| 338 | if (!packet_is_valid(packet))
|
---|
| 339 | return EINVAL;
|
---|
| 340 |
|
---|
| 341 | packet->order = order;
|
---|
| 342 | packet->metric = metric;
|
---|
| 343 | return EOK;
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | /** Sets the packet order and metric attributes.
|
---|
| 347 | *
|
---|
| 348 | * @param[in] packet The packet to be set.
|
---|
| 349 | * @param[out] order The packet order value.
|
---|
| 350 | * @param[out] metric The metric value of the packet.
|
---|
| 351 | * @returns EOK on success.
|
---|
| 352 | * @returns EINVAL if the packet is invalid.
|
---|
| 353 | */
|
---|
| 354 | int pq_get_order(packet_t packet, size_t *order, size_t *metric)
|
---|
| 355 | {
|
---|
| 356 | if (!packet_is_valid(packet))
|
---|
| 357 | return EINVAL;
|
---|
| 358 |
|
---|
| 359 | if (order)
|
---|
| 360 | *order = packet->order;
|
---|
| 361 |
|
---|
| 362 | if (metric)
|
---|
| 363 | *metric = packet->metric;
|
---|
| 364 |
|
---|
| 365 | return EOK;
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | /** Releases the whole queue.
|
---|
| 369 | *
|
---|
| 370 | * Detaches all packets of the queue and calls the packet_release() for each of
|
---|
| 371 | * them.
|
---|
| 372 | *
|
---|
| 373 | * @param[in] first The first packet of the queue.
|
---|
| 374 | * @param[in] packet_release The releasing function called for each of the
|
---|
| 375 | * packets after its detachment.
|
---|
| 376 | */
|
---|
| 377 | void pq_destroy(packet_t first, void (*packet_release)(packet_t packet))
|
---|
| 378 | {
|
---|
| 379 | packet_t actual;
|
---|
| 380 | packet_t next;
|
---|
| 381 |
|
---|
| 382 | actual = first;
|
---|
| 383 | while (packet_is_valid(actual)) {
|
---|
| 384 | next = pm_find(actual->next);
|
---|
| 385 | actual->next = 0;
|
---|
| 386 | actual->previous = 0;
|
---|
| 387 | if(packet_release)
|
---|
| 388 | packet_release(actual);
|
---|
| 389 | actual = next;
|
---|
| 390 | }
|
---|
| 391 | }
|
---|
| 392 |
|
---|
| 393 | /** Returns the next packet in the queue.
|
---|
| 394 | *
|
---|
| 395 | * @param[in] packet The packet queue member.
|
---|
| 396 | * @returns The next packet in the queue.
|
---|
| 397 | * @returns NULL if there is no next packet.
|
---|
| 398 | * @returns NULL if the packet is not valid.
|
---|
| 399 | */
|
---|
| 400 | packet_t pq_next(packet_t packet)
|
---|
| 401 | {
|
---|
| 402 | if (!packet_is_valid(packet))
|
---|
| 403 | return NULL;
|
---|
| 404 |
|
---|
| 405 | return pm_find(packet->next);
|
---|
| 406 | }
|
---|
| 407 |
|
---|
| 408 | /** Returns the previous packet in the queue.
|
---|
| 409 | *
|
---|
| 410 | * @param[in] packet The packet queue member.
|
---|
| 411 | * @returns The previous packet in the queue.
|
---|
| 412 | * @returns NULL if there is no previous packet.
|
---|
| 413 | * @returns NULL if the packet is not valid.
|
---|
| 414 | */
|
---|
| 415 | packet_t pq_previous(packet_t packet)
|
---|
| 416 | {
|
---|
| 417 | if (!packet_is_valid(packet))
|
---|
| 418 | return NULL;
|
---|
| 419 |
|
---|
| 420 | return pm_find(packet->previous);
|
---|
| 421 | }
|
---|
| 422 |
|
---|
| 423 | /** @}
|
---|
| 424 | */
|
---|