packet_server.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00037 #include <packet_server.h>
00038 
00039 #include <align.h>
00040 #include <assert.h>
00041 #include <async.h>
00042 #include <errno.h>
00043 #include <fibril_synch.h>
00044 #include <unistd.h>
00045 #include <sys/mman.h>
00046 #include <ipc/packet.h>
00047 #include <ipc/net.h>
00048 #include <net/packet.h>
00049 #include <net/packet_header.h>
00050 
00051 #define FREE_QUEUES_COUNT       7
00052 
00054 #define DEFAULT_ADDR_LEN        32
00055 
00057 #define DEFAULT_PREFIX          64
00058 
00060 #define DEFAULT_SUFFIX          64
00061 
00063 static struct {
00065         fibril_mutex_t lock;
00067         packet_t *free[FREE_QUEUES_COUNT];
00068         
00074         size_t sizes[FREE_QUEUES_COUNT];
00075         
00077         unsigned int count;
00078 } ps_globals = {
00079         .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
00080         .free = {
00081                 NULL,
00082                 NULL,
00083                 NULL,
00084                 NULL,
00085                 NULL,
00086                 NULL,
00087                 NULL
00088         },
00089         .sizes = {
00090                 PAGE_SIZE,
00091                 PAGE_SIZE * 2,
00092                 PAGE_SIZE * 4,
00093                 PAGE_SIZE * 8,
00094                 PAGE_SIZE * 16,
00095                 PAGE_SIZE * 32,
00096                 PAGE_SIZE * 64
00097         },
00098         .count = 0
00099 };
00100 
00110 static void
00111 packet_init(packet_t *packet, size_t addr_len, size_t max_prefix,
00112     size_t max_content, size_t max_suffix)
00113 {
00114         /* Clear the packet content */
00115         bzero(((void *) packet) + sizeof(packet_t),
00116             packet->length - sizeof(packet_t));
00117         
00118         /* Clear the packet header */
00119         packet->order = 0;
00120         packet->metric = 0;
00121         packet->previous = 0;
00122         packet->next = 0;
00123         packet->addr_len = 0;
00124         packet->src_addr = sizeof(packet_t);
00125         packet->dest_addr = packet->src_addr + addr_len;
00126         packet->max_prefix = max_prefix;
00127         packet->max_content = max_content;
00128         packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
00129         packet->data_end = packet->data_start;
00130 }
00131 
00144 static packet_t *
00145 packet_create(size_t length, size_t addr_len, size_t max_prefix,
00146     size_t max_content, size_t max_suffix)
00147 {
00148         packet_t *packet;
00149         int rc;
00150 
00151         assert(fibril_mutex_is_locked(&ps_globals.lock));
00152 
00153         /* Already locked */
00154         packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
00155             MAP_SHARED | MAP_ANONYMOUS, 0, 0);
00156         if (packet == MAP_FAILED)
00157                 return NULL;
00158 
00159         ps_globals.count++;
00160         packet->packet_id = ps_globals.count;
00161         packet->length = length;
00162         packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
00163         packet->magic_value = PACKET_MAGIC_VALUE;
00164         rc = pm_add(packet);
00165         if (rc != EOK) {
00166                 munmap(packet, packet->length);
00167                 return NULL;
00168         }
00169         
00170         return packet;
00171 }
00172 
00187 static packet_t *
00188 packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
00189     size_t max_suffix)
00190 {
00191         size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
00192             max_prefix + max_content + max_suffix, PAGE_SIZE);
00193         
00194         fibril_mutex_lock(&ps_globals.lock);
00195         
00196         packet_t *packet;
00197         unsigned int index;
00198         
00199         for (index = 0; index < FREE_QUEUES_COUNT; index++) {
00200                 if ((length > ps_globals.sizes[index]) &&
00201                     (index < FREE_QUEUES_COUNT - 1))
00202                         continue;
00203                 
00204                 packet = ps_globals.free[index];
00205                 while (packet_is_valid(packet) && (packet->length < length))
00206                         packet = pm_find(packet->next);
00207                 
00208                 if (packet_is_valid(packet)) {
00209                         if (packet == ps_globals.free[index])
00210                                 ps_globals.free[index] = pq_detach(packet);
00211                         else
00212                                 pq_detach(packet);
00213                         
00214                         packet_init(packet, addr_len, max_prefix, max_content,
00215                             max_suffix);
00216                         fibril_mutex_unlock(&ps_globals.lock);
00217                         
00218                         return packet;
00219                 }
00220         }
00221         
00222         packet = packet_create(length, addr_len, max_prefix, max_content,
00223             max_suffix);
00224         
00225         fibril_mutex_unlock(&ps_globals.lock);
00226         
00227         return packet;
00228 }
00229 
00235 static void packet_release(packet_t *packet)
00236 {
00237         int index;
00238         int result;
00239 
00240         assert(fibril_mutex_is_locked(&ps_globals.lock));
00241 
00242         for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
00243             (packet->length > ps_globals.sizes[index]); index++) {
00244                 ;
00245         }
00246         
00247         result = pq_add(&ps_globals.free[index], packet, packet->length,
00248             packet->length);
00249         assert(result == EOK);
00250 }
00251 
00258 static int packet_release_wrapper(packet_id_t packet_id)
00259 {
00260         packet_t *packet;
00261 
00262         packet = pm_find(packet_id);
00263         if (!packet_is_valid(packet))
00264                 return ENOENT;
00265 
00266         fibril_mutex_lock(&ps_globals.lock);
00267         pq_destroy(packet, packet_release);
00268         fibril_mutex_unlock(&ps_globals.lock);
00269 
00270         return EOK;
00271 }
00272 
00282 static int packet_reply(packet_t *packet)
00283 {
00284         ipc_callid_t callid;
00285         size_t size;
00286 
00287         if (!packet_is_valid(packet))
00288                 return EINVAL;
00289 
00290         if (!async_share_in_receive(&callid, &size)) {
00291                 async_answer_0(callid, EINVAL);
00292                 return EINVAL;
00293         }
00294 
00295         if (size != packet->length) {
00296                 async_answer_0(callid, ENOMEM);
00297                 return ENOMEM;
00298         }
00299         
00300         return async_share_in_finalize(callid, packet,
00301             PROTO_READ | PROTO_WRITE);
00302 }
00303 
00319 int
00320 packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
00321     size_t *answer_count)
00322 {
00323         packet_t *packet;
00324 
00325         *answer_count = 0;
00326         switch (IPC_GET_IMETHOD(*call)) {
00327         case IPC_M_PHONE_HUNGUP:
00328                 return EOK;
00329         
00330         case NET_PACKET_CREATE_1:
00331                 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
00332                     IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
00333                 if (!packet)
00334                         return ENOMEM;
00335                 *answer_count = 2;
00336                 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
00337                 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
00338                 return EOK;
00339         
00340         case NET_PACKET_CREATE_4:
00341                 packet = packet_get_local(
00342                     ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
00343                     IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
00344                     DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
00345                     IPC_GET_CONTENT(*call),
00346                     DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
00347                 if (!packet)
00348                         return ENOMEM;
00349                 *answer_count = 2;
00350                 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
00351                 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
00352                 return EOK;
00353         
00354         case NET_PACKET_GET:
00355                 packet = pm_find(IPC_GET_ID(*call));
00356                 if (!packet_is_valid(packet))
00357                         return ENOENT;
00358                 return packet_reply(packet);
00359         
00360         case NET_PACKET_GET_SIZE:
00361                 packet = pm_find(IPC_GET_ID(*call));
00362                 if (!packet_is_valid(packet))
00363                         return ENOENT;
00364                 IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
00365                 *answer_count = 1;
00366                 return EOK;
00367         
00368         case NET_PACKET_RELEASE:
00369                 return packet_release_wrapper(IPC_GET_ID(*call));
00370         }
00371         
00372         return ENOTSUP;
00373 }
00374 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7