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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b7068da was 9cd8165, checked in by Jiri Svoboda <jiri@…>, 14 years ago

NIC does not need nic_device_id_t. Now it exists just inside net. Not sure if
we care to rename it since net is going away soon, anyway.

  • Property mode set to 100644
File size: 13.4 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
[609243f4]3 * Copyright (c) 2011 Radim Vansa
[8d7ec69d]4 * Copyright (c) 2011 Jiri Svoboda
[21580dd]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
[14f1db0]32 * @{
[21580dd]33 */
34
35/** @file
[14f1db0]36 * Dummy network interface layer module implementation.
37 * @see nildummy.h
[21580dd]38 */
39
[609243f4]40#include <assert.h>
[21580dd]41#include <async.h>
42#include <malloc.h>
43#include <mem.h>
44#include <stdio.h>
[19f857a]45#include <str.h>
[fe8dfa6]46#include <ipc/nil.h>
[514ee46]47#include <ipc/net.h>
[21580dd]48#include <ipc/services.h>
[c7a8442]49#include <net/modules.h>
[e526f08]50#include <net/device.h>
[797b704]51#include <il_remote.h>
[849ed54]52#include <adt/measured_strings.h>
[c69d327]53#include <net/packet.h>
[14f1db0]54#include <packet_remote.h>
[609243f4]55#include <packet_client.h>
56#include <device/nic.h>
[77a69ea]57#include <loc.h>
[fe8dfa6]58#include <nil_skel.h>
[21580dd]59#include "nildummy.h"
60
[3cd95ef]61/** The module name. */
[24ab58b3]62#define NAME "nildummy"
[849ed54]63
[3cd95ef]64/** Default maximum transmission unit. */
[14f1db0]65#define NET_DEFAULT_MTU 1500
[21580dd]66
[3cd95ef]67/** Network interface layer module global data. */
[14f1db0]68nildummy_globals_t nildummy_globals;
[21580dd]69
[14f1db0]70DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
[21580dd]71
[8d7ec69d]72static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall,
73 void *arg);
74
[9cd8165]75static int nildummy_device_state(nildummy_device_t *device, sysarg_t state)
[14f1db0]76{
[aadf01e]77 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[6b82009]78 if (nildummy_globals.proto.sess)
[9cd8165]79 il_device_state_msg(nildummy_globals.proto.sess,
80 device->device_id, state, nildummy_globals.proto.service);
[aadf01e]81 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[14f1db0]82
[21580dd]83 return EOK;
84}
85
[9cd8165]86static int nildummy_addr_changed(nildummy_device_t *device)
[8d7ec69d]87{
88 return ENOTSUP;
89}
90
[6b82009]91int nil_initialize(async_sess_t *sess)
[14f1db0]92{
[aadf01e]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);
[14f1db0]97
[6b82009]98 nildummy_globals.net_sess = sess;
99 nildummy_globals.proto.sess = NULL;
[fe8dfa6]100 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
[14f1db0]101
[aadf01e]102 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
103 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[14f1db0]104
[093c0a1]105 return rc;
[21580dd]106}
107
[14f1db0]108/** Register new device or updates the MTU of an existing one.
109 *
110 * Determine the device local hardware address.
111 *
[fe8dfa6]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 *
[14f1db0]124 */
[609243f4]125static int nildummy_device_message(nic_device_id_t device_id,
[77a69ea]126 service_id_t sid, size_t mtu)
[14f1db0]127{
[aadf01e]128 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
[fe8dfa6]129
[fb04cba8]130 /* An existing device? */
[fe8dfa6]131 nildummy_device_t *device =
132 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]133 if (device) {
[77a69ea]134 if (device->sid != sid) {
[609243f4]135 printf("Device %d exists, handles do not match\n",
136 device->device_id);
137 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[21580dd]138 return EEXIST;
139 }
[3cd95ef]140
[fb04cba8]141 /* Update MTU */
[3cd95ef]142 if (mtu > 0)
[21580dd]143 device->mtu = mtu;
[3cd95ef]144 else
[21580dd]145 device->mtu = NET_DEFAULT_MTU;
[3cd95ef]146
[49bd793b]147 printf("Device %d already exists (mtu: %zu)\n", device->device_id,
[609243f4]148 device->mtu);
[3cd95ef]149 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
150
[fb04cba8]151 /* Notify the upper layer module */
[3cd95ef]152 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[6b82009]153 if (nildummy_globals.proto.sess) {
154 il_mtu_changed_msg(nildummy_globals.proto.sess,
[3cd95ef]155 device->device_id, device->mtu,
156 nildummy_globals.proto.service);
[21580dd]157 }
[3cd95ef]158 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
159
160 return EOK;
161 }
162
[fb04cba8]163 /* Create a new device */
[4e5c7ba]164 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
[3cd95ef]165 if (!device)
166 return ENOMEM;
167
168 device->device_id = device_id;
[77a69ea]169 device->sid = sid;
[3cd95ef]170 if (mtu > 0)
171 device->mtu = mtu;
172 else
173 device->mtu = NET_DEFAULT_MTU;
[609243f4]174
[fb04cba8]175 /* Bind the device driver */
[77a69ea]176 device->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid,
[609243f4]177 IPC_FLAG_BLOCKING);
[6b82009]178 if (device->sess == NULL) {
[3cd95ef]179 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
180 free(device);
[6b82009]181 return ENOENT;
[3cd95ef]182 }
183
[9cd8165]184 int rc = nic_callback_create(device->sess, nildummy_nic_cb_conn,
185 device);
[8d7ec69d]186 if (rc != EOK) {
187 async_hangup(device->sess);
188
189 return ENOENT;
190 }
[609243f4]191
[fb04cba8]192 /* Get hardware address */
[8d7ec69d]193 rc = nic_get_address(device->sess, &device->addr);
[093c0a1]194 if (rc != EOK) {
[3cd95ef]195 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
196 free(device);
[093c0a1]197 return rc;
[21580dd]198 }
[3cd95ef]199
[609243f4]200 device->addr_len = ETH_ADDR;
201
[fb04cba8]202 /* Add to the cache */
[fe8dfa6]203 int index = nildummy_devices_add(&nildummy_globals.devices,
[3cd95ef]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
[609243f4]211 printf("%s: Device registered (id: %d, mtu: %zu)\n", NAME,
212 device->device_id, device->mtu);
[aadf01e]213 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[21580dd]214 return EOK;
215}
216
[14f1db0]217/** Return the device hardware address.
218 *
[fe8dfa6]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.
[14f1db0]225 *
226 */
[609243f4]227static int nildummy_addr_message(nic_device_id_t device_id, size_t *addrlen)
[14f1db0]228{
[609243f4]229 if (!addrlen)
[aadf01e]230 return EBADMEM;
[3cd95ef]231
[aadf01e]232 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]233
234 nildummy_device_t *device =
235 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]236 if (!device) {
[aadf01e]237 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]238 return ENOENT;
239 }
[fe8dfa6]240
[609243f4]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 }
[fe8dfa6]247
[609243f4]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;
[3cd95ef]262
[609243f4]263 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
264 return EOK;
[21580dd]265}
266
[14f1db0]267/** Return the device packet dimensions for sending.
268 *
[fe8dfa6]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.
[14f1db0]278 *
279 */
[609243f4]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)
[14f1db0]282{
[fe8dfa6]283 if ((!addr_len) || (!prefix) || (!content) || (!suffix))
[aadf01e]284 return EBADMEM;
[3cd95ef]285
[aadf01e]286 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]287
288 nildummy_device_t *device =
289 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]290 if (!device) {
[aadf01e]291 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]292 return ENOENT;
293 }
[fe8dfa6]294
[aadf01e]295 *content = device->mtu;
[fe8dfa6]296
[aadf01e]297 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[3cd95ef]298
[aadf01e]299 *addr_len = 0;
300 *prefix = 0;
301 *suffix = 0;
[21580dd]302 return EOK;
303}
304
[609243f4]305int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet)
[3cd95ef]306{
[aadf01e]307 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[fe8dfa6]308
[6b82009]309 if (nildummy_globals.proto.sess) {
[3cd95ef]310 do {
[fe8dfa6]311 packet_t *next = pq_detach(packet);
[6b82009]312 il_received_msg(nildummy_globals.proto.sess, device_id,
[3cd95ef]313 packet, nildummy_globals.proto.service);
[21580dd]314 packet = next;
[fe8dfa6]315 } while (packet);
[21580dd]316 }
[fe8dfa6]317
[aadf01e]318 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[3cd95ef]319
[21580dd]320 return EOK;
321}
322
[14f1db0]323/** Register receiving module service.
324 *
325 * Pass received packets for this service.
326 *
[fe8dfa6]327 * @param[in] service Module service.
[6b82009]328 * @param[in] sess Service session.
[fe8dfa6]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 *
[14f1db0]334 */
[6b82009]335static int nildummy_register_message(services_t service, async_sess_t *sess)
[14f1db0]336{
[aadf01e]337 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
[21580dd]338 nildummy_globals.proto.service = service;
[6b82009]339 nildummy_globals.proto.sess = sess;
[24ab58b3]340
[00d7e1b]341 printf("%s: Protocol registered (service: %#x)\n",
[6b82009]342 NAME, nildummy_globals.proto.service);
[24ab58b3]343
[aadf01e]344 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
[21580dd]345 return EOK;
346}
347
[14f1db0]348/** Send the packet queue.
349 *
[fe8dfa6]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 *
[14f1db0]358 */
[609243f4]359static int nildummy_send_message(nic_device_id_t device_id, packet_t *packet,
[fb04cba8]360 services_t sender)
[14f1db0]361{
[aadf01e]362 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]363
364 nildummy_device_t *device =
365 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]366 if (!device) {
[aadf01e]367 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]368 return ENOENT;
369 }
[fe8dfa6]370
[5cc9eba]371 packet_t *p = packet;
[6d8455d]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));
[fe8dfa6]379
[aadf01e]380 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[fe8dfa6]381
[21580dd]382 return EOK;
383}
384
[9cd8165]385static int nildummy_received(nildummy_device_t *device)
[1bc35b5]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
[9cd8165]403 return nil_received_msg_local(device->device_id, packet);
[1bc35b5]404}
405
[fe8dfa6]406int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
407 ipc_call_t *answer, size_t *answer_count)
[24ab58b3]408{
[46d4d9f]409 packet_t *packet;
[e417b96]410 size_t addrlen;
411 size_t prefix;
412 size_t suffix;
413 size_t content;
[093c0a1]414 int rc;
[24ab58b3]415
[aadf01e]416 *answer_count = 0;
[79ae36dd]417
418 if (!IPC_GET_IMETHOD(*call))
[3cd95ef]419 return EOK;
420
[6b82009]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
[79ae36dd]426 switch (IPC_GET_IMETHOD(*call)) {
[3cd95ef]427 case NET_NIL_DEVICE:
[774e6d1a]428 return nildummy_device_message(IPC_GET_DEVICE(*call),
[609243f4]429 IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
[3cd95ef]430
431 case NET_NIL_SEND:
[6b82009]432 rc = packet_translate_remote(nildummy_globals.net_sess,
[774e6d1a]433 &packet, IPC_GET_PACKET(*call));
[093c0a1]434 if (rc != EOK)
435 return rc;
[774e6d1a]436 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
437 IPC_GET_SERVICE(*call));
[3cd95ef]438
439 case NET_NIL_PACKET_SPACE:
[774e6d1a]440 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
[093c0a1]441 &addrlen, &prefix, &content, &suffix);
442 if (rc != EOK)
443 return rc;
[774e6d1a]444 IPC_SET_ADDR(*answer, addrlen);
445 IPC_SET_PREFIX(*answer, prefix);
446 IPC_SET_CONTENT(*answer, content);
447 IPC_SET_SUFFIX(*answer, suffix);
[3cd95ef]448 *answer_count = 4;
449 return EOK;
450
451 case NET_NIL_ADDR:
452 case NET_NIL_BROADCAST_ADDR:
[609243f4]453 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &addrlen);
[093c0a1]454 if (rc != EOK)
455 return rc;
[609243f4]456
457 IPC_SET_ADDR(*answer, addrlen);
458 *answer_count = 1;
459 return rc;
[21580dd]460 }
[24ab58b3]461
[21580dd]462 return ENOTSUP;
463}
464
[8d7ec69d]465static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
466{
[9cd8165]467 nildummy_device_t *device = (nildummy_device_t *)arg;
[8d7ec69d]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:
[9cd8165]481 rc = nildummy_device_state(device, IPC_GET_ARG1(call));
[8d7ec69d]482 async_answer_0(callid, (sysarg_t) rc);
483 break;
484 case NIC_EV_RECEIVED:
[9cd8165]485 rc = nildummy_received(device);
[8d7ec69d]486 async_answer_0(callid, (sysarg_t) rc);
487 break;
488 case NIC_EV_ADDR_CHANGED:
[9cd8165]489 rc = nildummy_addr_changed(device);
[8d7ec69d]490 async_answer_0(callid, (sysarg_t) rc);
491 break;
492 default:
493 async_answer_0(callid, ENOTSUP);
494 }
495 }
496}
497
498
[849ed54]499int main(int argc, char *argv[])
500{
501 /* Start the module */
[fe8dfa6]502 return nil_module_start(SERVICE_NILDUMMY);
[849ed54]503}
504
[21580dd]505/** @}
506 */
Note: See TracBrowser for help on using the repository browser.