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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 764d71e was 28a3e74, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Fix comment style.

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