source: mainline/uspace/srv/net/net/packet_server.c@ 1761268

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

cstyle (no change in functionality)

  • Property mode set to 100644
File size: 11.4 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Radim Vansa
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libpacket
31 * @{
32 */
33
34/** @file
35 * Packet server implementation.
36 */
37
38#include <align.h>
39#include <assert.h>
40#include <async.h>
41#include <errno.h>
42#include <str_error.h>
43#include <stdio.h>
44#include <fibril_synch.h>
45#include <unistd.h>
46#include <sys/mman.h>
47#include <ipc/packet.h>
48#include <ipc/net.h>
49#include <net/packet.h>
50#include <net/packet_header.h>
51
52#include "packet_server.h"
53
54#define PACKET_SERVER_PROFILE 1
55
56/** Number of queues cacheing the unused packets */
57#define FREE_QUEUES_COUNT 7
58/** Maximum number of packets in each queue */
59#define FREE_QUEUE_MAX_LENGTH 16
60
61/** The default address length reserved for new packets. */
62#define DEFAULT_ADDR_LEN 32
63
64/** The default prefix reserved for new packets. */
65#define DEFAULT_PREFIX 64
66
67/** The default suffix reserved for new packets. */
68#define DEFAULT_SUFFIX 64
69
70/** The queue with unused packets */
71typedef struct packet_queue {
72 packet_t *first; /**< First packet in the queue */
73 size_t packet_size; /**< Maximal size of the packets in this queue */
74 int count; /**< Length of the queue */
75} packet_queue_t;
76
77/** Packet server global data. */
78static struct {
79 /** Safety lock. */
80 fibril_mutex_t lock;
81 /** Free packet queues. */
82 packet_queue_t free_queues[FREE_QUEUES_COUNT];
83
84 /** Total packets allocated. */
85 packet_id_t next_id;
86} ps_globals = {
87 .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
88 .free_queues = {
89 { NULL, PAGE_SIZE, 0},
90 { NULL, PAGE_SIZE * 2, 0},
91 { NULL, PAGE_SIZE * 4, 0},
92 { NULL, PAGE_SIZE * 8, 0},
93 { NULL, PAGE_SIZE * 16, 0},
94 { NULL, PAGE_SIZE * 32, 0},
95 { NULL, PAGE_SIZE * 64, 0},
96 },
97 .next_id = 1
98};
99
100/** Clears and initializes the packet according to the given dimensions.
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.
108 */
109static void packet_init(packet_t *packet,
110 size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix)
111{
112 /* Clear the packet content */
113 bzero(((void *) packet) + sizeof(packet_t),
114 packet->length - sizeof(packet_t));
115
116 /* Clear the packet header */
117 packet->order = 0;
118 packet->metric = 0;
119 packet->previous = 0;
120 packet->next = 0;
121 packet->offload_info = 0;
122 packet->offload_mask = 0;
123 packet->addr_len = 0;
124 packet->src_addr = sizeof(packet_t);
125 packet->dest_addr = packet->src_addr + addr_len;
126 packet->max_prefix = max_prefix;
127 packet->max_content = max_content;
128 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
129 packet->data_end = packet->data_start;
130}
131
132/**
133 * Releases the memory allocated for the packet
134 *
135 * @param[in] packet Pointer to the memory where the packet was allocated
136 */
137static void packet_dealloc(packet_t *packet)
138{
139 pm_remove(packet);
140 munmap(packet, packet->length);
141}
142
143/** Creates a new packet of dimensions at least as given.
144 *
145 * @param[in] length The total length of the packet, including the header,
146 * the addresses and the data of the packet.
147 * @param[in] addr_len The source and destination addresses maximal length in
148 * bytes.
149 * @param[in] max_prefix The maximal prefix length in bytes.
150 * @param[in] max_content The maximal content length in bytes.
151 * @param[in] max_suffix The maximal suffix length in bytes.
152 * @return The packet of dimensions at least as given.
153 * @return NULL if there is not enough memory left.
154 */
155static packet_t *packet_alloc(size_t length, size_t addr_len,
156 size_t max_prefix, size_t max_content, size_t max_suffix)
157{
158 packet_t *packet;
159 int rc;
160
161 /* Global lock is locked */
162 assert(fibril_mutex_is_locked(&ps_globals.lock));
163 /* The length is some multiple of PAGE_SIZE */
164 assert(!(length & (PAGE_SIZE - 1)));
165
166 packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
167 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
168 if (packet == MAP_FAILED)
169 return NULL;
170
171 /* Using 32bit packet_id the id could overflow */
172 packet_id_t pid;
173 do {
174 pid = ps_globals.next_id;
175 ps_globals.next_id++;
176 } while (!pid || pm_find(pid));
177 packet->packet_id = pid;
178
179 packet->length = length;
180 packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
181 packet->magic_value = PACKET_MAGIC_VALUE;
182 rc = pm_add(packet);
183 if (rc != EOK) {
184 packet_dealloc(packet);
185 return NULL;
186 }
187
188 return packet;
189}
190
191/** Return the packet of dimensions at least as given.
192 *
193 * Try to reuse free packets first.
194 * Create a new packet aligned to the memory page size if none available.
195 * Lock the global data during its processing.
196 *
197 * @param[in] addr_len The source and destination addresses maximal length in
198 * bytes.
199 * @param[in] max_prefix The maximal prefix length in bytes.
200 * @param[in] max_content The maximal content length in bytes.
201 * @param[in] max_suffix The maximal suffix length in bytes.
202 * @return The packet of dimensions at least as given.
203 * @return NULL if there is not enough memory left.
204 */
205static packet_t *packet_get_local(size_t addr_len,
206 size_t max_prefix, size_t max_content, size_t max_suffix)
207{
208 size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len
209 + max_prefix + max_content + max_suffix, PAGE_SIZE);
210
211 if (length > PACKET_MAX_LENGTH)
212 return NULL;
213
214 fibril_mutex_lock(&ps_globals.lock);
215
216 packet_t *packet;
217 unsigned int index;
218
219 for (index = 0; index < FREE_QUEUES_COUNT; index++) {
220 if ((length > ps_globals.free_queues[index].packet_size) &&
221 (index < FREE_QUEUES_COUNT - 1))
222 continue;
223
224 packet = ps_globals.free_queues[index].first;
225 while (packet_is_valid(packet) && (packet->length < length))
226 packet = pm_find(packet->next);
227
228 if (packet_is_valid(packet)) {
229 ps_globals.free_queues[index].count--;
230 if (packet == ps_globals.free_queues[index].first) {
231 ps_globals.free_queues[index].first = pq_detach(packet);
232 } else {
233 pq_detach(packet);
234 }
235
236 packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
237 fibril_mutex_unlock(&ps_globals.lock);
238
239 return packet;
240 }
241 }
242
243 packet = packet_alloc(length, addr_len,
244 max_prefix, max_content, max_suffix);
245
246 fibril_mutex_unlock(&ps_globals.lock);
247
248 return packet;
249}
250
251/** Release the packet and returns it to the appropriate free packet queue.
252 *
253 * @param[in] packet The packet to be released.
254 *
255 */
256static void packet_release(packet_t *packet)
257{
258 int index;
259 int result;
260
261 assert(fibril_mutex_is_locked(&ps_globals.lock));
262
263 for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
264 (packet->length > ps_globals.free_queues[index].packet_size); index++) {
265 ;
266 }
267
268 ps_globals.free_queues[index].count++;
269 result = pq_add(&ps_globals.free_queues[index].first, packet,
270 packet->length, packet->length);
271 assert(result == EOK);
272}
273
274/** Releases the packet queue.
275 *
276 * @param[in] packet_id The first packet identifier.
277 * @return EOK on success.
278 * @return ENOENT if there is no such packet.
279 */
280static int packet_release_wrapper(packet_id_t packet_id)
281{
282 packet_t *packet;
283
284 packet = pm_find(packet_id);
285 if (!packet_is_valid(packet))
286 return ENOENT;
287
288 fibril_mutex_lock(&ps_globals.lock);
289 pq_destroy(packet, packet_release);
290 fibril_mutex_unlock(&ps_globals.lock);
291
292 return EOK;
293}
294
295/** Shares the packet memory block.
296 * @param[in] packet The packet to be shared.
297 * @return EOK on success.
298 * @return EINVAL if the packet is not valid.
299 * @return EINVAL if the calling module does not accept the memory.
300 * @return ENOMEM if the desired and actual sizes differ.
301 * @return Other error codes as defined for the
302 * async_share_in_finalize() function.
303 */
304static int packet_reply(packet_t *packet)
305{
306 if (!packet_is_valid(packet))
307 return EINVAL;
308
309 ipc_callid_t callid;
310 size_t size;
311 if (!async_share_in_receive(&callid, &size)) {
312 async_answer_0(callid, EINVAL);
313 return EINVAL;
314 }
315
316 if (size != packet->length) {
317 async_answer_0(callid, ENOMEM);
318 return ENOMEM;
319 }
320
321 return async_share_in_finalize(callid, packet,
322 PROTO_READ | PROTO_WRITE);
323}
324
325/** Processes the packet server message.
326 *
327 * @param[in] callid The message identifier.
328 * @param[in] call The message parameters.
329 * @param[out] answer The message answer parameters.
330 * @param[out] answer_count The last parameter for the actual answer in the
331 * answer parameter.
332 * @return EOK on success.
333 * @return ENOMEM if there is not enough memory left.
334 * @return ENOENT if there is no such packet as in the packet
335 * message parameter.
336 * @return ENOTSUP if the message is not known.
337 * @return Other error codes as defined for the
338 * packet_release_wrapper() function.
339 */
340int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
341 size_t *answer_count)
342{
343 packet_t *packet;
344
345 if (!IPC_GET_IMETHOD(*call))
346 return EOK;
347
348 *answer_count = 0;
349 switch (IPC_GET_IMETHOD(*call)) {
350 case NET_PACKET_CREATE_1:
351 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
352 IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
353 if (!packet)
354 return ENOMEM;
355 *answer_count = 2;
356 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
357 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
358 return EOK;
359
360 case NET_PACKET_CREATE_4:
361 packet = packet_get_local(
362 ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
363 IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
364 DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
365 IPC_GET_CONTENT(*call),
366 DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
367 if (!packet)
368 return ENOMEM;
369 *answer_count = 2;
370 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
371 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
372 return EOK;
373
374 case NET_PACKET_GET:
375 packet = pm_find(IPC_GET_ID(*call));
376 if (!packet_is_valid(packet))
377 return ENOENT;
378
379 return packet_reply(packet);
380
381 case NET_PACKET_GET_SIZE:
382 packet = pm_find(IPC_GET_ID(*call));
383 if (!packet_is_valid(packet))
384 return ENOENT;
385 IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
386 *answer_count = 1;
387 return EOK;
388
389 case NET_PACKET_RELEASE:
390 return packet_release_wrapper(IPC_GET_ID(*call));
391 }
392
393 return ENOTSUP;
394}
395
396int packet_server_init()
397{
398 return EOK;
399}
400
401/** @}
402 */
Note: See TracBrowser for help on using the repository browser.