source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 30b2d02

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 30b2d02 was 3cd95ef, checked in by Jakub Jermar <jakub@…>, 15 years ago

Cleanup in nildummy.

  • Property mode set to 100644
File size: 13.3 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 nildummy
30 * @{
31 */
32
33/** @file
34 * Dummy network interface layer module implementation.
35 * @see nildummy.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
42#include <str.h>
43#include <err.h>
44#include <ipc/ipc.h>
45#include <ipc/net.h>
46#include <ipc/services.h>
47
48#include <net/modules.h>
49#include <net/device.h>
50#include <netif_interface.h>
51#include <nil_interface.h>
52#include <il_interface.h>
53#include <adt/measured_strings.h>
54#include <net/packet.h>
55#include <packet_remote.h>
56#include <nil_local.h>
57
58#include "nildummy.h"
59
60/** The module name. */
61#define NAME "nildummy"
62
63/** Default maximum transmission unit. */
64#define NET_DEFAULT_MTU 1500
65
66/** Network interface layer module global data. */
67nildummy_globals_t nildummy_globals;
68
69DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
70
71int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
72{
73 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
74 if (nildummy_globals.proto.phone)
75 il_device_state_msg(nildummy_globals.proto.phone, device_id,
76 state, nildummy_globals.proto.service);
77 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
78
79 return EOK;
80}
81
82int nil_initialize(int net_phone)
83{
84 ERROR_DECLARE;
85
86 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
87 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
88 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
89 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
90
91 nildummy_globals.net_phone = net_phone;
92 nildummy_globals.proto.phone = 0;
93 ERROR_CODE = nildummy_devices_initialize(&nildummy_globals.devices);
94
95 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
96 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
97
98 return ERROR_CODE;
99}
100
101/** Process IPC messages from the registered device driver modules in an
102 * infinite loop.
103 *
104 * @param[in] iid The message identifier.
105 * @param[in,out] icall The message parameters.
106 */
107static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall)
108{
109 ERROR_DECLARE;
110
111 packet_t packet;
112
113 while (true) {
114 switch (IPC_GET_METHOD(*icall)) {
115 case NET_NIL_DEVICE_STATE:
116 ERROR_CODE = nil_device_state_msg_local(0,
117 IPC_GET_DEVICE(icall), IPC_GET_STATE(icall));
118 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
119 break;
120
121 case NET_NIL_RECEIVED:
122 if (ERROR_NONE(packet_translate_remote(
123 nildummy_globals.net_phone, &packet,
124 IPC_GET_PACKET(icall)))) {
125 ERROR_CODE = nil_received_msg_local(0,
126 IPC_GET_DEVICE(icall), packet, 0);
127 }
128 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
129 break;
130
131 default:
132 ipc_answer_0(iid, (ipcarg_t) ENOTSUP);
133 }
134
135 iid = async_get_call(icall);
136 }
137}
138
139/** Register new device or updates the MTU of an existing one.
140 *
141 * Determine the device local hardware address.
142 *
143 * @param[in] device_id The new device identifier.
144 * @param[in] service The device driver service.
145 * @param[in] mtu The device maximum transmission unit.
146 * @returns EOK on success.
147 * @returns EEXIST if the device with the different service exists.
148 * @returns ENOMEM if there is not enough memory left.
149 * @returns Other error codes as defined for the
150 * netif_bind_service() function.
151 * @returns Other error codes as defined for the
152 * netif_get_addr_req() function.
153 */
154static int
155nildummy_device_message(device_id_t device_id, services_t service, size_t mtu)
156{
157 ERROR_DECLARE;
158
159 nildummy_device_ref device;
160 int index;
161
162 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
163
164 // an existing device?
165 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
166 if (device) {
167 if (device->service != service) {
168 printf("Device %d already exists\n", device->device_id);
169 fibril_rwlock_write_unlock(
170 &nildummy_globals.devices_lock);
171 return EEXIST;
172 }
173
174 // update mtu
175 if (mtu > 0)
176 device->mtu = mtu;
177 else
178 device->mtu = NET_DEFAULT_MTU;
179
180 printf("Device %d already exists:\tMTU\t= %d\n",
181 device->device_id, device->mtu);
182 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
183
184 // notify the upper layer module
185 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
186 if (nildummy_globals.proto.phone) {
187 il_mtu_changed_msg(nildummy_globals.proto.phone,
188 device->device_id, device->mtu,
189 nildummy_globals.proto.service);
190 }
191 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
192
193 return EOK;
194 }
195
196 // create a new device
197 device = (nildummy_device_ref) malloc(sizeof(nildummy_device_t));
198 if (!device)
199 return ENOMEM;
200
201 device->device_id = device_id;
202 device->service = service;
203 if (mtu > 0)
204 device->mtu = mtu;
205 else
206 device->mtu = NET_DEFAULT_MTU;
207
208 // bind the device driver
209 device->phone = netif_bind_service(device->service, device->device_id,
210 SERVICE_ETHERNET, nildummy_receiver);
211 if (device->phone < 0) {
212 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
213 free(device);
214 return device->phone;
215 }
216
217 // get hardware address
218 if (ERROR_OCCURRED(netif_get_addr_req(device->phone, device->device_id,
219 &device->addr, &device->addr_data))) {
220 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
221 free(device);
222 return ERROR_CODE;
223 }
224
225 // add to the cache
226 index = nildummy_devices_add(&nildummy_globals.devices,
227 device->device_id, device);
228 if (index < 0) {
229 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
230 free(device->addr);
231 free(device->addr_data);
232 free(device);
233 return index;
234 }
235
236 printf("%s: Device registered (id: %d, service: %d, mtu: %d)\n",
237 NAME, device->device_id, device->service, device->mtu);
238 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
239 return EOK;
240}
241
242/** Return the device hardware address.
243 *
244 * @param[in] device_id The device identifier.
245 * @param[out] address The device hardware address.
246 * @return EOK on success.
247 * @return EBADMEM if the address parameter is NULL.
248 * @return ENOENT if there no such device.
249 *
250 */
251static int
252nildummy_addr_message(device_id_t device_id, measured_string_ref *address)
253{
254 nildummy_device_ref device;
255
256 if (!address)
257 return EBADMEM;
258
259 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
260 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
261 if (!device) {
262 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
263 return ENOENT;
264 }
265 *address = device->addr;
266 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
267
268 return (*address) ? EOK : ENOENT;
269}
270
271/** Return the device packet dimensions for sending.
272 *
273 * @param[in] device_id The device identifier.
274 * @param[out] addr_len The minimum reserved address length.
275 * @param[out] prefix The minimum reserved prefix size.
276 * @param[out] content The maximum content size.
277 * @param[out] suffix The minimum reserved suffix size.
278 * @return EOK on success.
279 * @return EBADMEM if either one of the parameters is NULL.
280 * @return ENOENT if there is no such device.
281 *
282 */
283static int
284nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
285 size_t *prefix, size_t *content, size_t *suffix)
286{
287 nildummy_device_ref device;
288
289 if (!addr_len || !prefix || !content || !suffix)
290 return EBADMEM;
291
292 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
293 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
294 if (!device) {
295 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
296 return ENOENT;
297 }
298 *content = device->mtu;
299 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
300
301 *addr_len = 0;
302 *prefix = 0;
303 *suffix = 0;
304 return EOK;
305}
306
307int
308nil_received_msg_local(int nil_phone, device_id_t device_id, packet_t packet,
309 services_t target)
310{
311 packet_t next;
312
313 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
314 if (nildummy_globals.proto.phone) {
315 do {
316 next = pq_detach(packet);
317 il_received_msg(nildummy_globals.proto.phone, device_id,
318 packet, nildummy_globals.proto.service);
319 packet = next;
320 } while(packet);
321 }
322 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
323
324 return EOK;
325}
326
327/** Register receiving module service.
328 *
329 * Pass received packets for this service.
330 *
331 * @param[in] service The module service.
332 * @param[in] phone The service phone.
333 * @return EOK on success.
334 * @return ENOENT if the service is not known.
335 * @return ENOMEM if there is not enough memory left.
336 */
337static int nildummy_register_message(services_t service, int phone)
338{
339 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
340 nildummy_globals.proto.service = service;
341 nildummy_globals.proto.phone = phone;
342
343 printf("%s: Protocol registered (service: %d, phone: %d)\n",
344 NAME, nildummy_globals.proto.service, nildummy_globals.proto.phone);
345
346 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
347 return EOK;
348}
349
350/** Send the packet queue.
351 *
352 * @param[in] device_id The device identifier.
353 * @param[in] packet The packet queue.
354 * @param[in] sender The sending module service.
355 * @return EOK on success.
356 * @return ENOENT if there no such device.
357 * @return EINVAL if the service parameter is not known.
358 */
359static int
360nildummy_send_message(device_id_t device_id, packet_t packet, services_t sender)
361{
362 nildummy_device_ref device;
363
364 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
365 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
366 if (!device) {
367 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
368 return ENOENT;
369 }
370 // send packet queue
371 if (packet)
372 netif_send_msg(device->phone, device_id, packet,
373 SERVICE_NILDUMMY);
374 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
375 return EOK;
376}
377
378int
379nil_message_standalone(const char *name, ipc_callid_t callid, ipc_call_t *call,
380 ipc_call_t *answer, int *answer_count)
381{
382 ERROR_DECLARE;
383
384 measured_string_ref address;
385 packet_t packet;
386 size_t addrlen;
387 size_t prefix;
388 size_t suffix;
389 size_t content;
390
391 *answer_count = 0;
392 switch (IPC_GET_METHOD(*call)) {
393 case IPC_M_PHONE_HUNGUP:
394 return EOK;
395
396 case NET_NIL_DEVICE:
397 return nildummy_device_message(IPC_GET_DEVICE(call),
398 IPC_GET_SERVICE(call), IPC_GET_MTU(call));
399
400 case NET_NIL_SEND:
401 ERROR_PROPAGATE(packet_translate_remote(
402 nildummy_globals.net_phone, &packet, IPC_GET_PACKET(call)));
403 return nildummy_send_message(IPC_GET_DEVICE(call), packet,
404 IPC_GET_SERVICE(call));
405
406 case NET_NIL_PACKET_SPACE:
407 ERROR_PROPAGATE(nildummy_packet_space_message(
408 IPC_GET_DEVICE(call), &addrlen, &prefix, &content,
409 &suffix));
410 IPC_SET_ADDR(answer, addrlen);
411 IPC_SET_PREFIX(answer, prefix);
412 IPC_SET_CONTENT(answer, content);
413 IPC_SET_SUFFIX(answer, suffix);
414 *answer_count = 4;
415 return EOK;
416
417 case NET_NIL_ADDR:
418 ERROR_PROPAGATE(nildummy_addr_message(IPC_GET_DEVICE(call),
419 &address));
420 return measured_strings_reply(address, 1);
421
422 case NET_NIL_BROADCAST_ADDR:
423 ERROR_PROPAGATE(nildummy_addr_message(IPC_GET_DEVICE(call),
424 &address));
425 return measured_strings_reply(address, 1);
426
427 case IPC_M_CONNECT_TO_ME:
428 return nildummy_register_message(NIL_GET_PROTO(call),
429 IPC_GET_PHONE(call));
430 }
431
432 return ENOTSUP;
433}
434
435/** Default thread for new connections.
436 *
437 * @param[in] iid The initial message identifier.
438 * @param[in] icall The initial message call structure.
439 */
440static void nil_client_connection(ipc_callid_t iid, ipc_call_t *icall)
441{
442 /*
443 * Accept the connection
444 * - Answer the first IPC_M_CONNECT_ME_TO call.
445 */
446 ipc_answer_0(iid, EOK);
447
448 while (true) {
449 ipc_call_t answer;
450 int answer_count;
451
452 /* Clear the answer structure */
453 refresh_answer(&answer, &answer_count);
454
455 /* Fetch the next message */
456 ipc_call_t call;
457 ipc_callid_t callid = async_get_call(&call);
458
459 /* Process the message */
460 int res = nil_module_message_standalone(NAME, callid, &call,
461 &answer, &answer_count);
462
463 /*
464 * End if told to either by the message or the processing
465 * result.
466 */
467 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
468 (res == EHANGUP))
469 return;
470
471 /* Answer the message */
472 answer_call(callid, res, &answer, answer_count);
473 }
474}
475
476int main(int argc, char *argv[])
477{
478 ERROR_DECLARE;
479
480 /* Start the module */
481 ERROR_PROPAGATE(nil_module_start_standalone(nil_client_connection));
482 return EOK;
483}
484
485/** @}
486 */
Note: See TracBrowser for help on using the repository browser.