2
* Copyright (c) 2009 Lukas Mejdrech
3
* Copyright (c) 2011 Radim Vansa
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
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.
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.
30
/** @addtogroup libpacket
35
* Packet server implementation.
42
#include <str_error.h>
44
#include <fibril_synch.h>
47
#include <ipc/packet.h>
49
#include <net/packet.h>
50
#include <net/packet_header.h>
52
#include "packet_server.h"
54
#define PACKET_SERVER_PROFILE 1
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
61
/** The default address length reserved for new packets. */
62
#define DEFAULT_ADDR_LEN 32
64
/** The default prefix reserved for new packets. */
65
#define DEFAULT_PREFIX 64
67
/** The default suffix reserved for new packets. */
68
#define DEFAULT_SUFFIX 64
70
/** The queue with unused packets */
71
typedef 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 */
77
/** Packet server global data. */
81
/** Free packet queues. */
82
packet_queue_t free_queues[FREE_QUEUES_COUNT];
84
/** Total packets allocated. */
87
.lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
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},
100
/** Clears and initializes the packet according to the given dimensions.
102
* @param[in] packet The packet to be initialized.
103
* @param[in] addr_len The source and destination addresses maximal length in
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.
109
static void packet_init(packet_t *packet,
110
size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix)
112
/* Clear the packet content */
113
bzero(((void *) packet) + sizeof(packet_t),
114
packet->length - sizeof(packet_t));
116
/* Clear the packet header */
119
packet->previous = 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;
133
* Releases the memory allocated for the packet
135
* @param[in] packet Pointer to the memory where the packet was allocated
137
static void packet_dealloc(packet_t *packet)
140
munmap(packet, packet->length);
143
/** Creates a new packet of dimensions at least as given.
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
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.
155
static packet_t *packet_alloc(size_t length, size_t addr_len,
156
size_t max_prefix, size_t max_content, size_t max_suffix)
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)));
166
packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
167
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
168
if (packet == MAP_FAILED)
171
/* Using 32bit packet_id the id could overflow */
174
pid = ps_globals.next_id;
175
ps_globals.next_id++;
176
} while (!pid || pm_find(pid));
177
packet->packet_id = pid;
179
packet->length = length;
180
packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
181
packet->magic_value = PACKET_MAGIC_VALUE;
184
packet_dealloc(packet);
191
/** Return the packet of dimensions at least as given.
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.
197
* @param[in] addr_len The source and destination addresses maximal length in
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.
205
static packet_t *packet_get_local(size_t addr_len,
206
size_t max_prefix, size_t max_content, size_t max_suffix)
208
size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len
209
+ max_prefix + max_content + max_suffix, PAGE_SIZE);
211
if (length > PACKET_MAX_LENGTH)
214
fibril_mutex_lock(&ps_globals.lock);
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))
224
packet = ps_globals.free_queues[index].first;
225
while (packet_is_valid(packet) && (packet->length < length))
226
packet = pm_find(packet->next);
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);
236
packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
237
fibril_mutex_unlock(&ps_globals.lock);
243
packet = packet_alloc(length, addr_len,
244
max_prefix, max_content, max_suffix);
246
fibril_mutex_unlock(&ps_globals.lock);
251
/** Release the packet and returns it to the appropriate free packet queue.
253
* @param[in] packet The packet to be released.
256
static void packet_release(packet_t *packet)
261
assert(fibril_mutex_is_locked(&ps_globals.lock));
263
for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
264
(packet->length > ps_globals.free_queues[index].packet_size); index++) {
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);
274
/** Releases the packet queue.
276
* @param[in] packet_id The first packet identifier.
277
* @return EOK on success.
278
* @return ENOENT if there is no such packet.
280
static int packet_release_wrapper(packet_id_t packet_id)
284
packet = pm_find(packet_id);
285
if (!packet_is_valid(packet))
288
fibril_mutex_lock(&ps_globals.lock);
289
pq_destroy(packet, packet_release);
290
fibril_mutex_unlock(&ps_globals.lock);
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.
304
static int packet_reply(packet_t *packet)
306
if (!packet_is_valid(packet))
311
if (!async_share_in_receive(&callid, &size)) {
312
async_answer_0(callid, EINVAL);
316
if (size != packet->length) {
317
async_answer_0(callid, ENOMEM);
321
return async_share_in_finalize(callid, packet,
322
PROTO_READ | PROTO_WRITE);
325
/** Processes the packet server message.
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
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
336
* @return ENOTSUP if the message is not known.
337
* @return Other error codes as defined for the
338
* packet_release_wrapper() function.
340
int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
341
size_t *answer_count)
345
if (!IPC_GET_IMETHOD(*call))
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);
356
IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
357
IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
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));
370
IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
371
IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
375
packet = pm_find(IPC_GET_ID(*call));
376
if (!packet_is_valid(packet))
379
return packet_reply(packet);
381
case NET_PACKET_GET_SIZE:
382
packet = pm_find(IPC_GET_ID(*call));
383
if (!packet_is_valid(packet))
385
IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
389
case NET_PACKET_RELEASE:
390
return packet_release_wrapper(IPC_GET_ID(*call));
396
int packet_server_init()