source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 711e7fe5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 711e7fe5 was 711e7fe5, checked in by Prutkov Alex <prutkov.alex@…>, 14 years ago

Added printf module

  • Property mode set to 100755
File size: 13.4 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Radim Vansa
4 * Copyright (c) 2011 Jiri Svoboda
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup nildummy
32 * @{
33 */
34
35/** @file
36 * Dummy network interface layer module implementation.
37 * @see nildummy.h
38 */
39
40#include <assert.h>
41#include <async.h>
42#include <malloc.h>
43#include <mem.h>
44#include <stdio.h>
45#include <str.h>
46#include <ipc/nil.h>
47#include <ipc/net.h>
48#include <ipc/services.h>
49#include <net/modules.h>
50#include <net/device.h>
51#include <il_remote.h>
52#include <adt/measured_strings.h>
53#include <net/packet.h>
54#include <packet_remote.h>
55#include <packet_client.h>
56#include <device/nic.h>
57#include <loc.h>
58#include <nil_skel.h>
59#include "nildummy.h"
60
61/** The module name. */
62#define NAME "nildummy"
63
64/** Default maximum transmission unit. */
65#define NET_DEFAULT_MTU 1500
66
67/** Network interface layer module global data. */
68nildummy_globals_t nildummy_globals;
69
70DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
71
72static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall,
73 void *arg);
74
75static int nildummy_device_state(nildummy_device_t *device, sysarg_t state)
76{
77 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
78 if (nildummy_globals.proto.sess)
79 il_device_state_msg(nildummy_globals.proto.sess,
80 device->device_id, state, nildummy_globals.proto.service);
81 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
82
83 return EOK;
84}
85
86static int nildummy_addr_changed(nildummy_device_t *device)
87{
88 return ENOTSUP;
89}
90
91int nil_initialize(async_sess_t *sess)
92{
93 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
94 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
95 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
96 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
97
98 nildummy_globals.net_sess = sess;
99 nildummy_globals.proto.sess = NULL;
100 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
101
102 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
103 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
104
105 return rc;
106}
107
108/** Register new device or updates the MTU of an existing one.
109 *
110 * Determine the device local hardware address.
111 *
112 * @param[in] device_id New device identifier.
113 * @param[in] service Device driver service.
114 * @param[in] mtu Device maximum transmission unit.
115 *
116 * @return EOK on success.
117 * @return EEXIST if the device with the different service exists.
118 * @return ENOMEM if there is not enough memory left.
119 * @return Other error codes as defined for the
120 * netif_bind_service() function.
121 * @return Other error codes as defined for the
122 * netif_get_addr_req() function.
123 *
124 */
125static int nildummy_device_message(nic_device_id_t device_id,
126 service_id_t sid, size_t mtu)
127{
128 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
129
130 /* An existing device? */
131 nildummy_device_t *device =
132 nildummy_devices_find(&nildummy_globals.devices, device_id);
133 if (device) {
134 if (device->sid != sid) {
135 printf("Device %d exists, handles do not match\n",
136 device->device_id);
137 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
138 return EEXIST;
139 }
140
141 /* Update MTU */
142 if (mtu > 0)
143 device->mtu = mtu;
144 else
145 device->mtu = NET_DEFAULT_MTU;
146
147 printf("Device %d already exists (mtu: %zu)\n", device->device_id,
148 device->mtu);
149 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
150
151 /* Notify the upper layer module */
152 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
153 if (nildummy_globals.proto.sess) {
154 il_mtu_changed_msg(nildummy_globals.proto.sess,
155 device->device_id, device->mtu,
156 nildummy_globals.proto.service);
157 }
158 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
159
160 return EOK;
161 }
162
163 /* Create a new device */
164 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
165 if (!device)
166 return ENOMEM;
167
168 device->device_id = device_id;
169 device->sid = sid;
170 if (mtu > 0)
171 device->mtu = mtu;
172 else
173 device->mtu = NET_DEFAULT_MTU;
174
175 /* Bind the device driver */
176 device->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid,
177 IPC_FLAG_BLOCKING);
178 if (device->sess == NULL) {
179 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
180 free(device);
181 return ENOENT;
182 }
183
184 int rc = nic_callback_create(device->sess, nildummy_nic_cb_conn,
185 device);
186 if (rc != EOK) {
187 async_hangup(device->sess);
188
189 return ENOENT;
190 }
191
192 /* Get hardware address */
193 rc = nic_get_address(device->sess, &device->addr);
194 if (rc != EOK) {
195 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
196 free(device);
197 return rc;
198 }
199
200 device->addr_len = ETH_ADDR;
201
202 /* Add to the cache */
203 int index = nildummy_devices_add(&nildummy_globals.devices,
204 device->device_id, device);
205 if (index < 0) {
206 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
207 free(device);
208 return index;
209 }
210
211 printf("%s: Device registered (id: %d, mtu: %zu)\n", NAME,
212 device->device_id, device->mtu);
213 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
214 return EOK;
215}
216
217/** Return the device hardware address.
218 *
219 * @param[in] device_id Device identifier.
220 * @param[out] address Device hardware address.
221 *
222 * @return EOK on success.
223 * @return EBADMEM if the address parameter is NULL.
224 * @return ENOENT if there no such device.
225 *
226 */
227static int nildummy_addr_message(nic_device_id_t device_id, size_t *addrlen)
228{
229 if (!addrlen)
230 return EBADMEM;
231
232 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
233
234 nildummy_device_t *device =
235 nildummy_devices_find(&nildummy_globals.devices, device_id);
236 if (!device) {
237 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
238 return ENOENT;
239 }
240
241 ipc_callid_t callid;
242 size_t max_len;
243 if (!async_data_read_receive(&callid, &max_len)) {
244 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
245 return EREFUSED;
246 }
247
248 if (max_len < device->addr_len) {
249 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
250 async_data_read_finalize(callid, NULL, 0);
251 return ELIMIT;
252 }
253
254 int rc = async_data_read_finalize(callid,
255 (uint8_t *) &device->addr.address, device->addr_len);
256 if (rc != EOK) {
257 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
258 return rc;
259 }
260
261 *addrlen = device->addr_len;
262
263 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
264 return EOK;
265}
266
267/** Return the device packet dimensions for sending.
268 *
269 * @param[in] device_id Device identifier.
270 * @param[out] addr_len Minimum reserved address length.
271 * @param[out] prefix Minimum reserved prefix size.
272 * @param[out] content Maximum content size.
273 * @param[out] suffix Minimum reserved suffix size.
274 *
275 * @return EOK on success.
276 * @return EBADMEM if either one of the parameters is NULL.
277 * @return ENOENT if there is no such device.
278 *
279 */
280static int nildummy_packet_space_message(nic_device_id_t device_id,
281 size_t *addr_len, size_t *prefix, size_t *content, size_t *suffix)
282{
283 if ((!addr_len) || (!prefix) || (!content) || (!suffix))
284 return EBADMEM;
285
286 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
287
288 nildummy_device_t *device =
289 nildummy_devices_find(&nildummy_globals.devices, device_id);
290 if (!device) {
291 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
292 return ENOENT;
293 }
294
295 *content = device->mtu;
296
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(nic_device_id_t device_id, packet_t *packet)
306{
307 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
308
309 if (nildummy_globals.proto.sess) {
310 do {
311 packet_t *next = pq_detach(packet);
312 il_received_msg(nildummy_globals.proto.sess, device_id,
313 packet, nildummy_globals.proto.service);
314 packet = next;
315 } while (packet);
316 }
317
318 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
319
320 return EOK;
321}
322
323/** Register receiving module service.
324 *
325 * Pass received packets for this service.
326 *
327 * @param[in] service Module service.
328 * @param[in] sess Service session.
329 *
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 *
334 */
335static int nildummy_register_message(services_t service, async_sess_t *sess)
336{
337 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
338 nildummy_globals.proto.service = service;
339 nildummy_globals.proto.sess = sess;
340
341 printf("%s: Protocol registered (service: %#x)\n",
342 NAME, nildummy_globals.proto.service);
343
344 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
345 return EOK;
346}
347
348/** Send the packet queue.
349 *
350 * @param[in] device_id Device identifier.
351 * @param[in] packet Packet queue.
352 * @param[in] sender Sending module service.
353 *
354 * @return EOK on success.
355 * @return ENOENT if there no such device.
356 * @return EINVAL if the service parameter is not known.
357 *
358 */
359static int nildummy_send_message(nic_device_id_t device_id, packet_t *packet,
360 services_t sender)
361{
362 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
363
364 nildummy_device_t *device =
365 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
371 packet_t *p = packet;
372 do {
373 nic_send_frame(device->sess, packet_get_data(p),
374 packet_get_data_length(p));
375 p = pq_next(p);
376 } while (p != NULL);
377
378 pq_release_remote(nildummy_globals.net_sess, packet_get_id(packet));
379
380 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
381
382 return EOK;
383}
384
385static int nildummy_received(nildummy_device_t *device)
386{
387 void *data;
388 size_t size;
389 int rc;
390
391 rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
392 if (rc != EOK)
393 return rc;
394
395 packet_t *packet = packet_get_1_remote(nildummy_globals.net_sess, size);
396 if (packet == NULL)
397 return ENOMEM;
398
399 void *pdata = packet_suffix(packet, size);
400 memcpy(pdata, data, size);
401 free(pdata);
402
403 return nil_received_msg_local(device->device_id, packet);
404}
405
406int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
407 ipc_call_t *answer, size_t *answer_count)
408{
409 packet_t *packet;
410 size_t addrlen;
411 size_t prefix;
412 size_t suffix;
413 size_t content;
414 int rc;
415
416 *answer_count = 0;
417
418 if (!IPC_GET_IMETHOD(*call))
419 return EOK;
420
421 async_sess_t *callback =
422 async_callback_receive_start(EXCHANGE_SERIALIZE, call);
423 if (callback)
424 return nildummy_register_message(NIL_GET_PROTO(*call), callback);
425
426 switch (IPC_GET_IMETHOD(*call)) {
427 case NET_NIL_DEVICE:
428 return nildummy_device_message(IPC_GET_DEVICE(*call),
429 IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
430
431 case NET_NIL_SEND:
432 rc = packet_translate_remote(nildummy_globals.net_sess,
433 &packet, IPC_GET_PACKET(*call));
434 if (rc != EOK)
435 return rc;
436 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
437 IPC_GET_SERVICE(*call));
438
439 case NET_NIL_PACKET_SPACE:
440 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
441 &addrlen, &prefix, &content, &suffix);
442 if (rc != EOK)
443 return rc;
444 IPC_SET_ADDR(*answer, addrlen);
445 IPC_SET_PREFIX(*answer, prefix);
446 IPC_SET_CONTENT(*answer, content);
447 IPC_SET_SUFFIX(*answer, suffix);
448 *answer_count = 4;
449 return EOK;
450
451 case NET_NIL_ADDR:
452 case NET_NIL_BROADCAST_ADDR:
453 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &addrlen);
454 if (rc != EOK)
455 return rc;
456
457 IPC_SET_ADDR(*answer, addrlen);
458 *answer_count = 1;
459 return rc;
460 }
461
462 return ENOTSUP;
463}
464
465static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
466{
467 nildummy_device_t *device = (nildummy_device_t *)arg;
468 int rc;
469
470 async_answer_0(iid, EOK);
471
472 while (true) {
473 ipc_call_t call;
474 ipc_callid_t callid = async_get_call(&call);
475
476 if (!IPC_GET_IMETHOD(call))
477 break;
478
479 switch (IPC_GET_IMETHOD(call)) {
480 case NIC_EV_DEVICE_STATE:
481 rc = nildummy_device_state(device, IPC_GET_ARG1(call));
482 async_answer_0(callid, (sysarg_t) rc);
483 break;
484 case NIC_EV_RECEIVED:
485 rc = nildummy_received(device);
486 async_answer_0(callid, (sysarg_t) rc);
487 break;
488 case NIC_EV_ADDR_CHANGED:
489 rc = nildummy_addr_changed(device);
490 async_answer_0(callid, (sysarg_t) rc);
491 break;
492 default:
493 async_answer_0(callid, ENOTSUP);
494 }
495 }
496}
497
498
499int main(int argc, char *argv[])
500{
501 /* Start the module */
502 return nil_module_start(SERVICE_NILDUMMY);
503}
504
505/** @}
506 */
Note: See TracBrowser for help on using the repository browser.