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

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

partial networking stack overhaul

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