source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 61bfc370

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 61bfc370 was 228e490, checked in by Martin Decky <martin@…>, 15 years ago

initial modifications for supporting declarative IPC interfaces

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