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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6b82009 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
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#include <align.h>
39#include <assert.h>
40#include <async.h>
41#include <errno.h>
42#include <fibril_synch.h>
43#include <unistd.h>
44#include <sys/mman.h>
45#include <ipc/packet.h>
46#include <ipc/net.h>
47#include <net/packet.h>
48#include <net/packet_header.h>
49
50#define FREE_QUEUES_COUNT 7
51
52/** The default address length reserved for new packets. */
53#define DEFAULT_ADDR_LEN 32
54
55/** The default prefix reserved for new packets. */
56#define DEFAULT_PREFIX 64
57
58/** The default suffix reserved for new packets. */
59#define DEFAULT_SUFFIX 64
60
61/** Packet server global data. */
62static struct {
63 /** Safety lock. */
64 fibril_mutex_t lock;
65 /** Free packet queues. */
66 packet_t *free[FREE_QUEUES_COUNT];
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.
72 */
73 size_t sizes[FREE_QUEUES_COUNT];
74
75 /** Total packets allocated. */
76 unsigned int count;
77} ps_globals = {
78 .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
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 },
97 .count = 0
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
110packet_init(packet_t *packet, size_t addr_len, size_t max_prefix,
111 size_t max_content, size_t max_suffix)
112{
113 /* Clear the packet content */
114 bzero(((void *) packet) + sizeof(packet_t),
115 packet->length - sizeof(packet_t));
116
117 /* Clear the packet header */
118 packet->order = 0;
119 packet->metric = 0;
120 packet->previous = 0;
121 packet->next = 0;
122 packet->addr_len = 0;
123 packet->src_addr = sizeof(packet_t);
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}
130
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.
140 * @return The packet of dimensions at least as given.
141 * @return NULL if there is not enough memory left.
142 */
143static packet_t *
144packet_create(size_t length, size_t addr_len, size_t max_prefix,
145 size_t max_content, size_t max_suffix)
146{
147 packet_t *packet;
148 int rc;
149
150 assert(fibril_mutex_is_locked(&ps_globals.lock));
151
152 /* Already locked */
153 packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
154 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
155 if (packet == MAP_FAILED)
156 return NULL;
157
158 ps_globals.count++;
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;
163 rc = pm_add(packet);
164 if (rc != EOK) {
165 munmap(packet, packet->length);
166 return NULL;
167 }
168
169 return packet;
170}
171
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 *
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.
181 * @param[in] max_content The maximal content length in bytes.
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.
185 */
186static packet_t *
187packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
188 size_t max_suffix)
189{
190 size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
191 max_prefix + max_content + max_suffix, PAGE_SIZE);
192
193 fibril_mutex_lock(&ps_globals.lock);
194
195 packet_t *packet;
196 unsigned int index;
197
198 for (index = 0; index < FREE_QUEUES_COUNT; index++) {
199 if ((length > ps_globals.sizes[index]) &&
200 (index < FREE_QUEUES_COUNT - 1))
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);
212
213 packet_init(packet, addr_len, max_prefix, max_content,
214 max_suffix);
215 fibril_mutex_unlock(&ps_globals.lock);
216
217 return packet;
218 }
219 }
220
221 packet = packet_create(length, addr_len, max_prefix, max_content,
222 max_suffix);
223
224 fibril_mutex_unlock(&ps_globals.lock);
225
226 return packet;
227}
228
229/** Release the packet and returns it to the appropriate free packet queue.
230 *
231 * @param[in] packet The packet to be released.
232 *
233 */
234static void packet_release(packet_t *packet)
235{
236 int index;
237 int result;
238
239 assert(fibril_mutex_is_locked(&ps_globals.lock));
240
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);
248 assert(result == EOK);
249}
250
251/** Releases the packet queue.
252 *
253 * @param[in] packet_id The first packet identifier.
254 * @return EOK on success.
255 * @return ENOENT if there is no such packet.
256 */
257static int packet_release_wrapper(packet_id_t packet_id)
258{
259 packet_t *packet;
260
261 packet = pm_find(packet_id);
262 if (!packet_is_valid(packet))
263 return ENOENT;
264
265 fibril_mutex_lock(&ps_globals.lock);
266 pq_destroy(packet, packet_release);
267 fibril_mutex_unlock(&ps_globals.lock);
268
269 return EOK;
270}
271
272/** Shares the packet memory block.
273 * @param[in] packet The packet to be shared.
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
279 * async_share_in_finalize() function.
280 */
281static int packet_reply(packet_t *packet)
282{
283 ipc_callid_t callid;
284 size_t size;
285
286 if (!packet_is_valid(packet))
287 return EINVAL;
288
289 if (!async_share_in_receive(&callid, &size)) {
290 async_answer_0(callid, EINVAL);
291 return EINVAL;
292 }
293
294 if (size != packet->length) {
295 async_answer_0(callid, ENOMEM);
296 return ENOMEM;
297 }
298
299 return async_share_in_finalize(callid, packet,
300 PROTO_READ | PROTO_WRITE);
301}
302
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.
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
313 * message parameter.
314 * @return ENOTSUP if the message is not known.
315 * @return Other error codes as defined for the
316 * packet_release_wrapper() function.
317 */
318int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
319 size_t *answer_count)
320{
321 packet_t *packet;
322
323 if (!IPC_GET_IMETHOD(*call))
324 return EOK;
325
326 *answer_count = 0;
327 switch (IPC_GET_IMETHOD(*call)) {
328 case NET_PACKET_CREATE_1:
329 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
330 IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
331 if (!packet)
332 return ENOMEM;
333 *answer_count = 2;
334 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
335 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
336 return EOK;
337
338 case NET_PACKET_CREATE_4:
339 packet = packet_get_local(
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));
345 if (!packet)
346 return ENOMEM;
347 *answer_count = 2;
348 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
349 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
350 return EOK;
351
352 case NET_PACKET_GET:
353 packet = pm_find(IPC_GET_ID(*call));
354 if (!packet_is_valid(packet))
355 return ENOENT;
356 return packet_reply(packet);
357
358 case NET_PACKET_GET_SIZE:
359 packet = pm_find(IPC_GET_ID(*call));
360 if (!packet_is_valid(packet))
361 return ENOENT;
362 IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
363 *answer_count = 1;
364 return EOK;
365
366 case NET_PACKET_RELEASE:
367 return packet_release_wrapper(IPC_GET_ID(*call));
368 }
369
370 return ENOTSUP;
371}
372
373/** @}
374 */
Note: See TracBrowser for help on using the repository browser.