source: mainline/uspace/lib/packet/generic/packet_server.c@ 4b86dac

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4b86dac was 774e6d1a, checked in by martin@…>, 14 years ago

partial networking stack overhaul

  • a lot of coding style changes (comments, indentation, etc.)
  • convert several ints to unsigned ints or size_t values
  • streamline many of the IPC-related macros (they no longer dereference the call structure by themselves)
  • get rid of netif_interface.h (containing only aliases for remote functions and not serving any purpose)
  • rename netif_local.{c|h} to netif_skel.{c|h} (it is really just a skeleton)
  • drop the "_remote" and "_standalone" suffixes from most of the netif_ functions (they do not serve any purpose anymore)
  • implement netif_client_connection() as a common framework function for all netif modules
    • update the lo module accordingly
  • ip module now reports the default gateway to the user whenever it is being set
  • Property mode set to 100644
File size: 10.4 KB
RevLine 
[21580dd]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
[515a00da]29/** @addtogroup libpacket
[21580dd]30 * @{
31 */
32
33/** @file
[515a00da]34 * Packet server implementation.
[21580dd]35 */
36
[515a00da]37#include <packet_server.h>
38
[21580dd]39#include <align.h>
40#include <assert.h>
41#include <async.h>
42#include <errno.h>
43#include <fibril_synch.h>
44#include <unistd.h>
[d52fbaf]45#include <sys/mman.h>
[21580dd]46
47#include <ipc/ipc.h>
[d52fbaf]48#include <ipc/packet.h>
[514ee46]49#include <ipc/net.h>
50
[c69d327]51#include <net/packet.h>
52#include <net/packet_header.h>
[21580dd]53
54#define FREE_QUEUES_COUNT 7
55
[515a00da]56/** The default address length reserved for new packets. */
[21580dd]57#define DEFAULT_ADDR_LEN 32
58
[515a00da]59/** The default prefix reserved for new packets. */
[21580dd]60#define DEFAULT_PREFIX 64
61
[515a00da]62/** The default suffix reserved for new packets. */
[21580dd]63#define DEFAULT_SUFFIX 64
64
[515a00da]65/** Packet server global data. */
66static struct {
67 /** Safety lock. */
[21580dd]68 fibril_mutex_t lock;
[515a00da]69 /** Free packet queues. */
[46d4d9f]70 packet_t *free[FREE_QUEUES_COUNT];
[515a00da]71
72 /**
73 * Packet length upper bounds of the free packet queues. The maximal
74 * lengths of packets in each queue in the ascending order. The last
75 * queue is not limited.
[21580dd]76 */
[aadf01e]77 size_t sizes[FREE_QUEUES_COUNT];
[515a00da]78
79 /** Total packets allocated. */
[21580dd]80 unsigned int count;
81} ps_globals = {
[e721462]82 .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
[515a00da]83 .free = {
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL
91 },
92 .sizes = {
93 PAGE_SIZE,
94 PAGE_SIZE * 2,
95 PAGE_SIZE * 4,
96 PAGE_SIZE * 8,
97 PAGE_SIZE * 16,
98 PAGE_SIZE * 32,
99 PAGE_SIZE * 64
100 },
[21580dd]101 .count = 0
102};
103
[849ed54]104/** Clears and initializes the packet according to the given dimensions.
[515a00da]105 *
106 * @param[in] packet The packet to be initialized.
107 * @param[in] addr_len The source and destination addresses maximal length in
108 * bytes.
109 * @param[in] max_prefix The maximal prefix length in bytes.
110 * @param[in] max_content The maximal content length in bytes.
111 * @param[in] max_suffix The maximal suffix length in bytes.
[21580dd]112 */
[515a00da]113static void
[46d4d9f]114packet_init(packet_t *packet, size_t addr_len, size_t max_prefix,
[515a00da]115 size_t max_content, size_t max_suffix)
116{
[849ed54]117 // clear the packet content
[46d4d9f]118 bzero(((void *) packet) + sizeof(packet_t),
119 packet->length - sizeof(packet_t));
[515a00da]120
[849ed54]121 // clear the packet header
122 packet->order = 0;
123 packet->metric = 0;
124 packet->previous = 0;
125 packet->next = 0;
126 packet->addr_len = 0;
[46d4d9f]127 packet->src_addr = sizeof(packet_t);
[849ed54]128 packet->dest_addr = packet->src_addr + addr_len;
129 packet->max_prefix = max_prefix;
130 packet->max_content = max_content;
131 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
132 packet->data_end = packet->data_start;
133}
[21580dd]134
[515a00da]135/** Creates a new packet of dimensions at least as given.
136 *
137 * @param[in] length The total length of the packet, including the header,
138 * the addresses and the data of the packet.
139 * @param[in] addr_len The source and destination addresses maximal length in
140 * bytes.
141 * @param[in] max_prefix The maximal prefix length in bytes.
142 * @param[in] max_content The maximal content length in bytes.
143 * @param[in] max_suffix The maximal suffix length in bytes.
[1bfd3d3]144 * @return The packet of dimensions at least as given.
145 * @return NULL if there is not enough memory left.
[21580dd]146 */
[46d4d9f]147static packet_t *
[515a00da]148packet_create(size_t length, size_t addr_len, size_t max_prefix,
149 size_t max_content, size_t max_suffix)
150{
[46d4d9f]151 packet_t *packet;
[88b127b]152 int rc;
[849ed54]153
[01b87dc5]154 assert(fibril_mutex_is_locked(&ps_globals.lock));
155
[849ed54]156 // already locked
[46d4d9f]157 packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
[515a00da]158 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
159 if (packet == MAP_FAILED)
[849ed54]160 return NULL;
[515a00da]161
[9880813f]162 ps_globals.count++;
[849ed54]163 packet->packet_id = ps_globals.count;
164 packet->length = length;
165 packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
166 packet->magic_value = PACKET_MAGIC_VALUE;
[88b127b]167 rc = pm_add(packet);
168 if (rc != EOK) {
[849ed54]169 munmap(packet, packet->length);
170 return NULL;
171 }
[515a00da]172
[849ed54]173 return packet;
174}
175
[14f1db0]176/** Return the packet of dimensions at least as given.
177 *
178 * Try to reuse free packets first.
179 * Create a new packet aligned to the memory page size if none available.
180 * Lock the global data during its processing.
181 *
[515a00da]182 * @param[in] addr_len The source and destination addresses maximal length in
183 * bytes.
184 * @param[in] max_prefix The maximal prefix length in bytes.
[14f1db0]185 * @param[in] max_content The maximal content length in bytes.
[515a00da]186 * @param[in] max_suffix The maximal suffix length in bytes.
187 * @return The packet of dimensions at least as given.
188 * @return NULL if there is not enough memory left.
[21580dd]189 */
[46d4d9f]190static packet_t *
[515a00da]191packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
192 size_t max_suffix)
[14f1db0]193{
[46d4d9f]194 size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
[515a00da]195 max_prefix + max_content + max_suffix, PAGE_SIZE);
[14f1db0]196
[849ed54]197 fibril_mutex_lock(&ps_globals.lock);
[14f1db0]198
[46d4d9f]199 packet_t *packet;
[14f1db0]200 unsigned int index;
201
[279b80c]202 for (index = 0; index < FREE_QUEUES_COUNT; index++) {
[376a7fd]203 if ((length > ps_globals.sizes[index]) &&
204 (index < FREE_QUEUES_COUNT - 1))
[515a00da]205 continue;
206
207 packet = ps_globals.free[index];
208 while (packet_is_valid(packet) && (packet->length < length))
209 packet = pm_find(packet->next);
210
211 if (packet_is_valid(packet)) {
212 if (packet == ps_globals.free[index])
213 ps_globals.free[index] = pq_detach(packet);
214 else
215 pq_detach(packet);
[14f1db0]216
[515a00da]217 packet_init(packet, addr_len, max_prefix, max_content,
218 max_suffix);
219 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]220
[515a00da]221 return packet;
[849ed54]222 }
[aadf01e]223 }
[14f1db0]224
225 packet = packet_create(length, addr_len, max_prefix, max_content,
226 max_suffix);
227
[849ed54]228 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]229
[849ed54]230 return packet;
[21580dd]231}
232
[14f1db0]233/** Release the packet and returns it to the appropriate free packet queue.
234 *
[515a00da]235 * @param[in] packet The packet to be released.
[14f1db0]236 *
[849ed54]237 */
[46d4d9f]238static void packet_release(packet_t *packet)
[515a00da]239{
[849ed54]240 int index;
241 int result;
242
[01b87dc5]243 assert(fibril_mutex_is_locked(&ps_globals.lock));
244
[515a00da]245 for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
246 (packet->length > ps_globals.sizes[index]); index++) {
247 ;
248 }
249
250 result = pq_add(&ps_globals.free[index], packet, packet->length,
251 packet->length);
[849ed54]252 assert(result == EOK);
253}
254
255/** Releases the packet queue.
[515a00da]256 *
257 * @param[in] packet_id The first packet identifier.
[1bfd3d3]258 * @return EOK on success.
259 * @return ENOENT if there is no such packet.
[849ed54]260 */
[515a00da]261static int packet_release_wrapper(packet_id_t packet_id)
262{
[46d4d9f]263 packet_t *packet;
[849ed54]264
265 packet = pm_find(packet_id);
[515a00da]266 if (!packet_is_valid(packet))
[849ed54]267 return ENOENT;
[515a00da]268
[849ed54]269 fibril_mutex_lock(&ps_globals.lock);
270 pq_destroy(packet, packet_release);
271 fibril_mutex_unlock(&ps_globals.lock);
[515a00da]272
[849ed54]273 return EOK;
274}
275
276/** Shares the packet memory block.
[515a00da]277 * @param[in] packet The packet to be shared.
[1bfd3d3]278 * @return EOK on success.
279 * @return EINVAL if the packet is not valid.
280 * @return EINVAL if the calling module does not accept the memory.
281 * @return ENOMEM if the desired and actual sizes differ.
282 * @return Other error codes as defined for the
[515a00da]283 * async_share_in_finalize() function.
[849ed54]284 */
[46d4d9f]285static int packet_reply(packet_t *packet)
[515a00da]286{
[849ed54]287 ipc_callid_t callid;
288 size_t size;
289
[515a00da]290 if (!packet_is_valid(packet))
[849ed54]291 return EINVAL;
[515a00da]292
[57f737a]293 if (!async_share_in_receive(&callid, &size)) {
294 ipc_answer_0(callid, EINVAL);
[515a00da]295 return EINVAL;
[57f737a]296 }
[a649e73f]297
298 if (size != packet->length) {
299 ipc_answer_0(callid, ENOMEM);
300 return ENOMEM;
301 }
[515a00da]302
303 return async_share_in_finalize(callid, packet,
304 PROTO_READ | PROTO_WRITE);
[849ed54]305}
306
[515a00da]307/** Processes the packet server message.
308 *
309 * @param[in] callid The message identifier.
310 * @param[in] call The message parameters.
311 * @param[out] answer The message answer parameters.
312 * @param[out] answer_count The last parameter for the actual answer in the
313 * answer parameter.
[1bfd3d3]314 * @return EOK on success.
315 * @return ENOMEM if there is not enough memory left.
316 * @return ENOENT if there is no such packet as in the packet
[515a00da]317 * message parameter.
[1bfd3d3]318 * @return ENOTSUP if the message is not known.
319 * @return Other error codes as defined for the
[515a00da]320 * packet_release_wrapper() function.
321 */
322int
323packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
[774e6d1a]324 size_t *answer_count)
[515a00da]325{
[46d4d9f]326 packet_t *packet;
[21580dd]327
[aadf01e]328 *answer_count = 0;
[228e490]329 switch (IPC_GET_IMETHOD(*call)) {
[515a00da]330 case IPC_M_PHONE_HUNGUP:
331 return EOK;
332
333 case NET_PACKET_CREATE_1:
334 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
[774e6d1a]335 IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
[515a00da]336 if (!packet)
337 return ENOMEM;
338 *answer_count = 2;
[96b02eb9]339 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
340 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
[515a00da]341 return EOK;
342
343 case NET_PACKET_CREATE_4:
344 packet = packet_get_local(
[774e6d1a]345 ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
346 IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
347 DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
348 IPC_GET_CONTENT(*call),
349 DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
[515a00da]350 if (!packet)
351 return ENOMEM;
352 *answer_count = 2;
[96b02eb9]353 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
354 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
[515a00da]355 return EOK;
356
357 case NET_PACKET_GET:
[774e6d1a]358 packet = pm_find(IPC_GET_ID(*call));
[515a00da]359 if (!packet_is_valid(packet))
360 return ENOENT;
361 return packet_reply(packet);
362
363 case NET_PACKET_GET_SIZE:
[774e6d1a]364 packet = pm_find(IPC_GET_ID(*call));
[515a00da]365 if (!packet_is_valid(packet))
366 return ENOENT;
[96b02eb9]367 IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
[515a00da]368 *answer_count = 1;
369 return EOK;
370
371 case NET_PACKET_RELEASE:
[774e6d1a]372 return packet_release_wrapper(IPC_GET_ID(*call));
[21580dd]373 }
[515a00da]374
[21580dd]375 return ENOTSUP;
376}
377
378/** @}
379 */
Note: See TracBrowser for help on using the repository browser.