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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a4ee3ab2 was 6b82009, checked in by Martin Decky <martin@…>, 14 years ago

networking stack: convert to the new async framework

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