[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. */
|
---|
[46d4d9f] | 64 | typedef packet_t *packet_map_t[PACKET_MAP_SIZE];
|
---|
[c69d327] | 65 |
|
---|
| 66 | /** Packet map.
|
---|
| 67 | * Maps packet identifiers to the packet references.
|
---|
| 68 | * @see generic_field.h
|
---|
| 69 | */
|
---|
| 70 | GENERIC_FIELD_DECLARE(gpm, packet_map_t);
|
---|
| 71 |
|
---|
| 72 | /** Packet map global data. */
|
---|
| 73 | static struct {
|
---|
| 74 | /** Safety lock. */
|
---|
| 75 | fibril_rwlock_t lock;
|
---|
| 76 | /** Packet map. */
|
---|
| 77 | gpm_t packet_map;
|
---|
| 78 | } pm_globals;
|
---|
| 79 |
|
---|
| 80 | GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
|
---|
| 81 |
|
---|
| 82 | /** Initializes the packet map.
|
---|
| 83 | *
|
---|
[1bfd3d3] | 84 | * @return EOK on success.
|
---|
| 85 | * @return ENOMEM if there is not enough memory left.
|
---|
[c69d327] | 86 | */
|
---|
| 87 | int pm_init(void)
|
---|
| 88 | {
|
---|
[16ac756] | 89 | int rc;
|
---|
[c69d327] | 90 |
|
---|
| 91 | fibril_rwlock_initialize(&pm_globals.lock);
|
---|
[16ac756] | 92 |
|
---|
[c69d327] | 93 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
[16ac756] | 94 | rc = gpm_initialize(&pm_globals.packet_map);
|
---|
[c69d327] | 95 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
[16ac756] | 96 |
|
---|
| 97 | return rc;
|
---|
[c69d327] | 98 | }
|
---|
| 99 |
|
---|
| 100 | /** Finds the packet mapping.
|
---|
| 101 | *
|
---|
| 102 | * @param[in] packet_id The packet identifier to be found.
|
---|
[1bfd3d3] | 103 | * @return The found packet reference.
|
---|
| 104 | * @return NULL if the mapping does not exist.
|
---|
[c69d327] | 105 | */
|
---|
[46d4d9f] | 106 | packet_t *pm_find(packet_id_t packet_id)
|
---|
[c69d327] | 107 | {
|
---|
[88a1bb9] | 108 | packet_map_t *map;
|
---|
[46d4d9f] | 109 | packet_t *packet;
|
---|
[c69d327] | 110 |
|
---|
| 111 | if (!packet_id)
|
---|
| 112 | return NULL;
|
---|
| 113 |
|
---|
| 114 | fibril_rwlock_read_lock(&pm_globals.lock);
|
---|
| 115 | if (packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)) {
|
---|
| 116 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 117 | return NULL;
|
---|
| 118 | }
|
---|
| 119 | map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
|
---|
| 120 | if (!map) {
|
---|
| 121 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 122 | return NULL;
|
---|
| 123 | }
|
---|
| 124 | packet = (*map) [PACKET_MAP_INDEX(packet_id)];
|
---|
| 125 | fibril_rwlock_read_unlock(&pm_globals.lock);
|
---|
| 126 | return packet;
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | /** Adds the packet mapping.
|
---|
| 130 | *
|
---|
| 131 | * @param[in] packet The packet to be remembered.
|
---|
[1bfd3d3] | 132 | * @return EOK on success.
|
---|
| 133 | * @return EINVAL if the packet is not valid.
|
---|
| 134 | * @return EINVAL if the packet map is not initialized.
|
---|
| 135 | * @return ENOMEM if there is not enough memory left.
|
---|
[c69d327] | 136 | */
|
---|
[46d4d9f] | 137 | int pm_add(packet_t *packet)
|
---|
[c69d327] | 138 | {
|
---|
[88a1bb9] | 139 | packet_map_t *map;
|
---|
[16ac756] | 140 | int rc;
|
---|
[c69d327] | 141 |
|
---|
| 142 | if (!packet_is_valid(packet))
|
---|
| 143 | return EINVAL;
|
---|
| 144 |
|
---|
| 145 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
| 146 |
|
---|
| 147 | if (PACKET_MAP_PAGE(packet->packet_id) <
|
---|
| 148 | gpm_count(&pm_globals.packet_map)) {
|
---|
| 149 | map = gpm_get_index(&pm_globals.packet_map,
|
---|
| 150 | PACKET_MAP_PAGE(packet->packet_id));
|
---|
| 151 | } else {
|
---|
| 152 | do {
|
---|
[88a1bb9] | 153 | map = (packet_map_t *) malloc(sizeof(packet_map_t));
|
---|
[c69d327] | 154 | if (!map) {
|
---|
| 155 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 156 | return ENOMEM;
|
---|
| 157 | }
|
---|
| 158 | bzero(map, sizeof(packet_map_t));
|
---|
[16ac756] | 159 | rc = gpm_add(&pm_globals.packet_map, map);
|
---|
| 160 | if (rc < 0) {
|
---|
[c69d327] | 161 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 162 | free(map);
|
---|
[16ac756] | 163 | return rc;
|
---|
[c69d327] | 164 | }
|
---|
| 165 | } while (PACKET_MAP_PAGE(packet->packet_id) >=
|
---|
| 166 | gpm_count(&pm_globals.packet_map));
|
---|
| 167 | }
|
---|
| 168 |
|
---|
| 169 | (*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
|
---|
| 170 | fibril_rwlock_write_unlock(&pm_globals.lock);
|
---|
| 171 | return EOK;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | /** Releases the packet map. */
|
---|
| 175 | void pm_destroy(void)
|
---|
| 176 | {
|
---|
| 177 | int count;
|
---|
| 178 | int index;
|
---|
[88a1bb9] | 179 | packet_map_t *map;
|
---|
[46d4d9f] | 180 | packet_t *packet;
|
---|
[c69d327] | 181 |
|
---|
| 182 | fibril_rwlock_write_lock(&pm_globals.lock);
|
---|
| 183 | count = gpm_count(&pm_globals.packet_map);
|
---|
| 184 | while (count > 0) {
|
---|
| 185 | map = gpm_get_index(&pm_globals.packet_map, count - 1);
|
---|
| 186 | for (index = PACKET_MAP_SIZE - 1; index >= 0; --index) {
|
---|
| 187 | packet = (*map)[index];
|
---|
| 188 | if (packet_is_valid(packet))
|
---|
| 189 | munmap(packet, packet->length);
|
---|
| 190 | }
|
---|
| 191 | }
|
---|
| 192 | gpm_destroy(&pm_globals.packet_map);
|
---|
[45bb1d2] | 193 | /* leave locked */
|
---|
[c69d327] | 194 | }
|
---|
| 195 |
|
---|
| 196 | /** Add packet to the sorted queue.
|
---|
| 197 | *
|
---|
| 198 | * The queue is sorted in the ascending order.
|
---|
| 199 | * The packet is inserted right before the packets of the same order value.
|
---|
| 200 | *
|
---|
| 201 | * @param[in,out] first The first packet of the queue. Sets the first packet of
|
---|
| 202 | * the queue. The original first packet may be shifted by
|
---|
| 203 | * the new packet.
|
---|
| 204 | * @param[in] packet The packet to be added.
|
---|
| 205 | * @param[in] order The packet order value.
|
---|
| 206 | * @param[in] metric The metric value of the packet.
|
---|
[1bfd3d3] | 207 | * @return EOK on success.
|
---|
| 208 | * @return EINVAL if the first parameter is NULL.
|
---|
| 209 | * @return EINVAL if the packet is not valid.
|
---|
[c69d327] | 210 | */
|
---|
[46d4d9f] | 211 | int pq_add(packet_t **first, packet_t *packet, size_t order, size_t metric)
|
---|
[c69d327] | 212 | {
|
---|
[46d4d9f] | 213 | packet_t *item;
|
---|
[c69d327] | 214 |
|
---|
| 215 | if (!first || !packet_is_valid(packet))
|
---|
| 216 | return EINVAL;
|
---|
| 217 |
|
---|
| 218 | pq_set_order(packet, order, metric);
|
---|
| 219 | if (packet_is_valid(*first)) {
|
---|
| 220 | item = * first;
|
---|
| 221 | do {
|
---|
| 222 | if (item->order < order) {
|
---|
| 223 | if (item->next) {
|
---|
| 224 | item = pm_find(item->next);
|
---|
| 225 | } else {
|
---|
| 226 | item->next = packet->packet_id;
|
---|
| 227 | packet->previous = item->packet_id;
|
---|
| 228 | return EOK;
|
---|
| 229 | }
|
---|
| 230 | } else {
|
---|
| 231 | packet->previous = item->previous;
|
---|
| 232 | packet->next = item->packet_id;
|
---|
| 233 | item->previous = packet->packet_id;
|
---|
| 234 | item = pm_find(packet->previous);
|
---|
| 235 | if (item)
|
---|
| 236 | item->next = packet->packet_id;
|
---|
| 237 | else
|
---|
| 238 | *first = packet;
|
---|
| 239 | return EOK;
|
---|
| 240 | }
|
---|
| 241 | } while (packet_is_valid(item));
|
---|
| 242 | }
|
---|
| 243 | *first = packet;
|
---|
| 244 | return EOK;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | /** Finds the packet with the given order.
|
---|
| 248 | *
|
---|
| 249 | * @param[in] first The first packet of the queue.
|
---|
| 250 | * @param[in] order The packet order value.
|
---|
[1bfd3d3] | 251 | * @return The packet with the given order.
|
---|
| 252 | * @return NULL if the first packet is not valid.
|
---|
| 253 | * @return NULL if the packet is not found.
|
---|
[c69d327] | 254 | */
|
---|
[46d4d9f] | 255 | packet_t *pq_find(packet_t *packet, size_t order)
|
---|
[c69d327] | 256 | {
|
---|
[46d4d9f] | 257 | packet_t *item;
|
---|
[c69d327] | 258 |
|
---|
| 259 | if (!packet_is_valid(packet))
|
---|
| 260 | return NULL;
|
---|
| 261 |
|
---|
| 262 | item = packet;
|
---|
| 263 | do {
|
---|
| 264 | if (item->order == order)
|
---|
| 265 | return item;
|
---|
| 266 |
|
---|
| 267 | item = pm_find(item->next);
|
---|
| 268 | } while (item && (item != packet) && packet_is_valid(item));
|
---|
| 269 |
|
---|
| 270 | return NULL;
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | /** Inserts packet after the given one.
|
---|
| 274 | *
|
---|
| 275 | * @param[in] packet The packet in the queue.
|
---|
| 276 | * @param[in] new_packet The new packet to be inserted.
|
---|
[1bfd3d3] | 277 | * @return EOK on success.
|
---|
| 278 | * @return EINVAL if etiher of the packets is invalid.
|
---|
[c69d327] | 279 | */
|
---|
[46d4d9f] | 280 | int pq_insert_after(packet_t *packet, packet_t *new_packet)
|
---|
[c69d327] | 281 | {
|
---|
[46d4d9f] | 282 | packet_t *item;
|
---|
[c69d327] | 283 |
|
---|
| 284 | if (!packet_is_valid(packet) || !packet_is_valid(new_packet))
|
---|
| 285 | return EINVAL;
|
---|
| 286 |
|
---|
| 287 | new_packet->previous = packet->packet_id;
|
---|
| 288 | new_packet->next = packet->next;
|
---|
| 289 | item = pm_find(packet->next);
|
---|
| 290 | if (item)
|
---|
| 291 | item->previous = new_packet->packet_id;
|
---|
| 292 | packet->next = new_packet->packet_id;
|
---|
| 293 |
|
---|
| 294 | return EOK;
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | /** Detach the packet from the queue.
|
---|
| 298 | *
|
---|
| 299 | * @param[in] packet The packet to be detached.
|
---|
[1bfd3d3] | 300 | * @return The next packet in the queue. If the packet is the first
|
---|
[c69d327] | 301 | * one of the queue, this becomes the new first one.
|
---|
[1bfd3d3] | 302 | * @return NULL if there is no packet left.
|
---|
| 303 | * @return NULL if the packet is not valid.
|
---|
[c69d327] | 304 | */
|
---|
[46d4d9f] | 305 | packet_t *pq_detach(packet_t *packet)
|
---|
[c69d327] | 306 | {
|
---|
[46d4d9f] | 307 | packet_t *next;
|
---|
| 308 | packet_t *previous;
|
---|
[c69d327] | 309 |
|
---|
| 310 | if (!packet_is_valid(packet))
|
---|
| 311 | return NULL;
|
---|
| 312 |
|
---|
| 313 | next = pm_find(packet->next);
|
---|
| 314 | if (next) {
|
---|
| 315 | next->previous = packet->previous;
|
---|
| 316 | previous = pm_find(next->previous);
|
---|
| 317 | if (previous)
|
---|
| 318 | previous->next = next->packet_id;
|
---|
| 319 | }
|
---|
| 320 | packet->previous = 0;
|
---|
| 321 | packet->next = 0;
|
---|
| 322 | return next;
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 | /** Sets the packet order and metric attributes.
|
---|
| 326 | *
|
---|
| 327 | * @param[in] packeti The packet to be set.
|
---|
| 328 | * @param[in] order The packet order value.
|
---|
| 329 | * @param[in] metric The metric value of the packet.
|
---|
[1bfd3d3] | 330 | * @return EOK on success.
|
---|
| 331 | * @return EINVAL if the packet is invalid.
|
---|
[c69d327] | 332 | */
|
---|
[46d4d9f] | 333 | int pq_set_order(packet_t *packet, size_t order, size_t metric)
|
---|
[c69d327] | 334 | {
|
---|
| 335 | if (!packet_is_valid(packet))
|
---|
| 336 | return EINVAL;
|
---|
| 337 |
|
---|
| 338 | packet->order = order;
|
---|
| 339 | packet->metric = metric;
|
---|
| 340 | return EOK;
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | /** Sets the packet order and metric attributes.
|
---|
| 344 | *
|
---|
| 345 | * @param[in] packet The packet to be set.
|
---|
| 346 | * @param[out] order The packet order value.
|
---|
| 347 | * @param[out] metric The metric value of the packet.
|
---|
[1bfd3d3] | 348 | * @return EOK on success.
|
---|
| 349 | * @return EINVAL if the packet is invalid.
|
---|
[c69d327] | 350 | */
|
---|
[46d4d9f] | 351 | int pq_get_order(packet_t *packet, size_t *order, size_t *metric)
|
---|
[c69d327] | 352 | {
|
---|
| 353 | if (!packet_is_valid(packet))
|
---|
| 354 | return EINVAL;
|
---|
| 355 |
|
---|
| 356 | if (order)
|
---|
| 357 | *order = packet->order;
|
---|
| 358 |
|
---|
| 359 | if (metric)
|
---|
| 360 | *metric = packet->metric;
|
---|
| 361 |
|
---|
| 362 | return EOK;
|
---|
| 363 | }
|
---|
| 364 |
|
---|
| 365 | /** Releases the whole queue.
|
---|
| 366 | *
|
---|
| 367 | * Detaches all packets of the queue and calls the packet_release() for each of
|
---|
| 368 | * them.
|
---|
| 369 | *
|
---|
| 370 | * @param[in] first The first packet of the queue.
|
---|
| 371 | * @param[in] packet_release The releasing function called for each of the
|
---|
| 372 | * packets after its detachment.
|
---|
| 373 | */
|
---|
[46d4d9f] | 374 | void pq_destroy(packet_t *first, void (*packet_release)(packet_t *packet))
|
---|
[c69d327] | 375 | {
|
---|
[46d4d9f] | 376 | packet_t *actual;
|
---|
| 377 | packet_t *next;
|
---|
[c69d327] | 378 |
|
---|
| 379 | actual = first;
|
---|
| 380 | while (packet_is_valid(actual)) {
|
---|
| 381 | next = pm_find(actual->next);
|
---|
| 382 | actual->next = 0;
|
---|
| 383 | actual->previous = 0;
|
---|
| 384 | if(packet_release)
|
---|
| 385 | packet_release(actual);
|
---|
| 386 | actual = next;
|
---|
| 387 | }
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | /** Returns the next packet in the queue.
|
---|
| 391 | *
|
---|
| 392 | * @param[in] packet The packet queue member.
|
---|
[1bfd3d3] | 393 | * @return The next packet in the queue.
|
---|
| 394 | * @return NULL if there is no next packet.
|
---|
| 395 | * @return NULL if the packet is not valid.
|
---|
[c69d327] | 396 | */
|
---|
[46d4d9f] | 397 | packet_t *pq_next(packet_t *packet)
|
---|
[c69d327] | 398 | {
|
---|
| 399 | if (!packet_is_valid(packet))
|
---|
| 400 | return NULL;
|
---|
| 401 |
|
---|
| 402 | return pm_find(packet->next);
|
---|
| 403 | }
|
---|
| 404 |
|
---|
| 405 | /** Returns the previous packet in the queue.
|
---|
| 406 | *
|
---|
| 407 | * @param[in] packet The packet queue member.
|
---|
[1bfd3d3] | 408 | * @return The previous packet in the queue.
|
---|
| 409 | * @return NULL if there is no previous packet.
|
---|
| 410 | * @return NULL if the packet is not valid.
|
---|
[c69d327] | 411 | */
|
---|
[46d4d9f] | 412 | packet_t *pq_previous(packet_t *packet)
|
---|
[c69d327] | 413 | {
|
---|
| 414 | if (!packet_is_valid(packet))
|
---|
| 415 | return NULL;
|
---|
| 416 |
|
---|
| 417 | return pm_find(packet->previous);
|
---|
| 418 | }
|
---|
| 419 |
|
---|
| 420 | /** @}
|
---|
| 421 | */
|
---|