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

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

networking stack: convert to the new async framework

  • Property mode set to 100644
File size: 12.3 KB
RevLine 
[21580dd]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
[14f1db0]30 * @{
[21580dd]31 */
32
33/** @file
[14f1db0]34 * Dummy network interface layer module implementation.
35 * @see nildummy.h
[21580dd]36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
[19f857a]42#include <str.h>
[fe8dfa6]43#include <ipc/nil.h>
[514ee46]44#include <ipc/net.h>
[21580dd]45#include <ipc/services.h>
[c7a8442]46#include <net/modules.h>
[e526f08]47#include <net/device.h>
[797b704]48#include <il_remote.h>
[849ed54]49#include <adt/measured_strings.h>
[c69d327]50#include <net/packet.h>
[14f1db0]51#include <packet_remote.h>
[774e6d1a]52#include <netif_remote.h>
[fe8dfa6]53#include <nil_skel.h>
[21580dd]54#include "nildummy.h"
55
[3cd95ef]56/** The module name. */
[24ab58b3]57#define NAME "nildummy"
[849ed54]58
[3cd95ef]59/** Default maximum transmission unit. */
[14f1db0]60#define NET_DEFAULT_MTU 1500
[21580dd]61
[3cd95ef]62/** Network interface layer module global data. */
[14f1db0]63nildummy_globals_t nildummy_globals;
[21580dd]64
[14f1db0]65DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
[21580dd]66
[6b82009]67int nil_device_state_msg_local(device_id_t device_id, sysarg_t state)
[14f1db0]68{
[aadf01e]69 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[6b82009]70 if (nildummy_globals.proto.sess)
71 il_device_state_msg(nildummy_globals.proto.sess, device_id,
[3cd95ef]72 state, nildummy_globals.proto.service);
[aadf01e]73 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[14f1db0]74
[21580dd]75 return EOK;
76}
77
[6b82009]78int nil_initialize(async_sess_t *sess)
[14f1db0]79{
[aadf01e]80 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
81 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
82 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
83 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
[14f1db0]84
[6b82009]85 nildummy_globals.net_sess = sess;
86 nildummy_globals.proto.sess = NULL;
[fe8dfa6]87 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
[14f1db0]88
[aadf01e]89 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
90 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[14f1db0]91
[093c0a1]92 return rc;
[21580dd]93}
94
[fe8dfa6]95/** Process IPC messages from the registered device driver modules
96 *
97 * @param[in] iid Message identifier.
98 * @param[in,out] icall Message parameters.
[6b82009]99 * @param[in] arg Local argument.
100 *
[14f1db0]101 */
[9934f7d]102static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[3cd95ef]103{
[46d4d9f]104 packet_t *packet;
[093c0a1]105 int rc;
[fe8dfa6]106
[3cd95ef]107 while (true) {
[228e490]108 switch (IPC_GET_IMETHOD(*icall)) {
[3cd95ef]109 case NET_NIL_DEVICE_STATE:
[6b82009]110 rc = nil_device_state_msg_local(IPC_GET_DEVICE(*icall),
111 IPC_GET_STATE(*icall));
[ffa2c8ef]112 async_answer_0(iid, (sysarg_t) rc);
[3cd95ef]113 break;
114
115 case NET_NIL_RECEIVED:
[6b82009]116 rc = packet_translate_remote(nildummy_globals.net_sess,
[774e6d1a]117 &packet, IPC_GET_PACKET(*icall));
[797b704]118 if (rc == EOK)
[6b82009]119 rc = nil_received_msg_local(IPC_GET_DEVICE(*icall),
120 packet, 0);
[797b704]121
[ffa2c8ef]122 async_answer_0(iid, (sysarg_t) rc);
[3cd95ef]123 break;
124
125 default:
[ffa2c8ef]126 async_answer_0(iid, (sysarg_t) ENOTSUP);
[14f1db0]127 }
[3cd95ef]128
[14f1db0]129 iid = async_get_call(icall);
130 }
131}
132
133/** Register new device or updates the MTU of an existing one.
134 *
135 * Determine the device local hardware address.
136 *
[fe8dfa6]137 * @param[in] device_id New device identifier.
138 * @param[in] service Device driver service.
139 * @param[in] mtu Device maximum transmission unit.
140 *
141 * @return EOK on success.
142 * @return EEXIST if the device with the different service exists.
143 * @return ENOMEM if there is not enough memory left.
144 * @return Other error codes as defined for the
145 * netif_bind_service() function.
146 * @return Other error codes as defined for the
147 * netif_get_addr_req() function.
148 *
[14f1db0]149 */
[fb04cba8]150static int nildummy_device_message(device_id_t device_id, services_t service,
151 size_t mtu)
[14f1db0]152{
[aadf01e]153 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
[fe8dfa6]154
[fb04cba8]155 /* An existing device? */
[fe8dfa6]156 nildummy_device_t *device =
157 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]158 if (device) {
159 if (device->service != service) {
[aadf01e]160 printf("Device %d already exists\n", device->device_id);
[3cd95ef]161 fibril_rwlock_write_unlock(
162 &nildummy_globals.devices_lock);
[21580dd]163 return EEXIST;
164 }
[3cd95ef]165
[fb04cba8]166 /* Update MTU */
[3cd95ef]167 if (mtu > 0)
[21580dd]168 device->mtu = mtu;
[3cd95ef]169 else
[21580dd]170 device->mtu = NET_DEFAULT_MTU;
[3cd95ef]171
[7e752b2]172 printf("Device %d already exists:\tMTU\t= %zu\n",
[3cd95ef]173 device->device_id, device->mtu);
174 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
175
[fb04cba8]176 /* Notify the upper layer module */
[3cd95ef]177 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[6b82009]178 if (nildummy_globals.proto.sess) {
179 il_mtu_changed_msg(nildummy_globals.proto.sess,
[3cd95ef]180 device->device_id, device->mtu,
181 nildummy_globals.proto.service);
[21580dd]182 }
[3cd95ef]183 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
184
185 return EOK;
186 }
187
[fb04cba8]188 /* Create a new device */
[4e5c7ba]189 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
[3cd95ef]190 if (!device)
191 return ENOMEM;
192
193 device->device_id = device_id;
194 device->service = service;
195 if (mtu > 0)
196 device->mtu = mtu;
197 else
198 device->mtu = NET_DEFAULT_MTU;
199
[fb04cba8]200 /* Bind the device driver */
[6b82009]201 device->sess = netif_bind_service(device->service, device->device_id,
[3cd95ef]202 SERVICE_ETHERNET, nildummy_receiver);
[6b82009]203 if (device->sess == NULL) {
[3cd95ef]204 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
205 free(device);
[6b82009]206 return ENOENT;
[3cd95ef]207 }
208
[fb04cba8]209 /* Get hardware address */
[6b82009]210 int rc = netif_get_addr_req(device->sess, device->device_id,
[fe8dfa6]211 &device->addr, &device->addr_data);
[093c0a1]212 if (rc != EOK) {
[3cd95ef]213 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
214 free(device);
[093c0a1]215 return rc;
[21580dd]216 }
[3cd95ef]217
[fb04cba8]218 /* Add to the cache */
[fe8dfa6]219 int index = nildummy_devices_add(&nildummy_globals.devices,
[3cd95ef]220 device->device_id, device);
221 if (index < 0) {
222 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
223 free(device->addr);
224 free(device->addr_data);
225 free(device);
226 return index;
227 }
228
[7e752b2]229 printf("%s: Device registered (id: %d, service: %d, mtu: %zu)\n",
[3cd95ef]230 NAME, device->device_id, device->service, device->mtu);
[aadf01e]231 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[21580dd]232 return EOK;
233}
234
[14f1db0]235/** Return the device hardware address.
236 *
[fe8dfa6]237 * @param[in] device_id Device identifier.
238 * @param[out] address Device hardware address.
239 *
240 * @return EOK on success.
241 * @return EBADMEM if the address parameter is NULL.
242 * @return ENOENT if there no such device.
[14f1db0]243 *
244 */
[fb04cba8]245static int nildummy_addr_message(device_id_t device_id,
[4eca056]246 measured_string_t **address)
[14f1db0]247{
[3cd95ef]248 if (!address)
[aadf01e]249 return EBADMEM;
[3cd95ef]250
[aadf01e]251 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]252
253 nildummy_device_t *device =
254 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]255 if (!device) {
[aadf01e]256 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]257 return ENOENT;
258 }
[fe8dfa6]259
[aadf01e]260 *address = device->addr;
[fe8dfa6]261
[aadf01e]262 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[3cd95ef]263
[aadf01e]264 return (*address) ? EOK : ENOENT;
[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 */
[fb04cba8]280static int nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
[3cd95ef]281 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
[6b82009]305int nil_received_msg_local(device_id_t device_id, packet_t *packet,
306 services_t target)
[3cd95ef]307{
[aadf01e]308 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[fe8dfa6]309
[6b82009]310 if (nildummy_globals.proto.sess) {
[3cd95ef]311 do {
[fe8dfa6]312 packet_t *next = pq_detach(packet);
[6b82009]313 il_received_msg(nildummy_globals.proto.sess, device_id,
[3cd95ef]314 packet, nildummy_globals.proto.service);
[21580dd]315 packet = next;
[fe8dfa6]316 } while (packet);
[21580dd]317 }
[fe8dfa6]318
[aadf01e]319 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[3cd95ef]320
[21580dd]321 return EOK;
322}
323
[14f1db0]324/** Register receiving module service.
325 *
326 * Pass received packets for this service.
327 *
[fe8dfa6]328 * @param[in] service Module service.
[6b82009]329 * @param[in] sess Service session.
[fe8dfa6]330 *
331 * @return EOK on success.
332 * @return ENOENT if the service is not known.
333 * @return ENOMEM if there is not enough memory left.
334 *
[14f1db0]335 */
[6b82009]336static int nildummy_register_message(services_t service, async_sess_t *sess)
[14f1db0]337{
[aadf01e]338 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
[21580dd]339 nildummy_globals.proto.service = service;
[6b82009]340 nildummy_globals.proto.sess = sess;
[24ab58b3]341
[6b82009]342 printf("%s: Protocol registered (service: %d)\n",
343 NAME, nildummy_globals.proto.service);
[24ab58b3]344
[aadf01e]345 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
[21580dd]346 return EOK;
347}
348
[14f1db0]349/** Send the packet queue.
350 *
[fe8dfa6]351 * @param[in] device_id Device identifier.
352 * @param[in] packet Packet queue.
353 * @param[in] sender Sending module service.
354 *
355 * @return EOK on success.
356 * @return ENOENT if there no such device.
357 * @return EINVAL if the service parameter is not known.
358 *
[14f1db0]359 */
[46d4d9f]360static int nildummy_send_message(device_id_t device_id, packet_t *packet,
[fb04cba8]361 services_t sender)
[14f1db0]362{
[aadf01e]363 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]364
365 nildummy_device_t *device =
366 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]367 if (!device) {
[aadf01e]368 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]369 return ENOENT;
370 }
[fe8dfa6]371
[fb04cba8]372 /* Send packet queue */
[3cd95ef]373 if (packet)
[6b82009]374 netif_send_msg(device->sess, device_id, packet,
[3cd95ef]375 SERVICE_NILDUMMY);
[fe8dfa6]376
[aadf01e]377 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[fe8dfa6]378
[21580dd]379 return EOK;
380}
381
[fe8dfa6]382int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
383 ipc_call_t *answer, size_t *answer_count)
[24ab58b3]384{
[4eca056]385 measured_string_t *address;
[46d4d9f]386 packet_t *packet;
[e417b96]387 size_t addrlen;
388 size_t prefix;
389 size_t suffix;
390 size_t content;
[093c0a1]391 int rc;
[24ab58b3]392
[aadf01e]393 *answer_count = 0;
[79ae36dd]394
395 if (!IPC_GET_IMETHOD(*call))
[3cd95ef]396 return EOK;
397
[6b82009]398 async_sess_t *callback =
399 async_callback_receive_start(EXCHANGE_SERIALIZE, call);
400 if (callback)
401 return nildummy_register_message(NIL_GET_PROTO(*call), callback);
402
[79ae36dd]403 switch (IPC_GET_IMETHOD(*call)) {
[3cd95ef]404 case NET_NIL_DEVICE:
[774e6d1a]405 return nildummy_device_message(IPC_GET_DEVICE(*call),
406 IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
[3cd95ef]407
408 case NET_NIL_SEND:
[6b82009]409 rc = packet_translate_remote(nildummy_globals.net_sess,
[774e6d1a]410 &packet, IPC_GET_PACKET(*call));
[093c0a1]411 if (rc != EOK)
412 return rc;
[774e6d1a]413 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
414 IPC_GET_SERVICE(*call));
[3cd95ef]415
416 case NET_NIL_PACKET_SPACE:
[774e6d1a]417 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
[093c0a1]418 &addrlen, &prefix, &content, &suffix);
419 if (rc != EOK)
420 return rc;
[774e6d1a]421 IPC_SET_ADDR(*answer, addrlen);
422 IPC_SET_PREFIX(*answer, prefix);
423 IPC_SET_CONTENT(*answer, content);
424 IPC_SET_SUFFIX(*answer, suffix);
[3cd95ef]425 *answer_count = 4;
426 return EOK;
427
428 case NET_NIL_ADDR:
[774e6d1a]429 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
[093c0a1]430 if (rc != EOK)
431 return rc;
[3cd95ef]432 return measured_strings_reply(address, 1);
433
434 case NET_NIL_BROADCAST_ADDR:
[774e6d1a]435 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
[093c0a1]436 if (rc != EOK)
437 return rc;
[3cd95ef]438 return measured_strings_reply(address, 1);
[21580dd]439 }
[24ab58b3]440
[21580dd]441 return ENOTSUP;
442}
443
[849ed54]444int main(int argc, char *argv[])
445{
446 /* Start the module */
[fe8dfa6]447 return nil_module_start(SERVICE_NILDUMMY);
[849ed54]448}
449
[21580dd]450/** @}
451 */
Note: See TracBrowser for help on using the repository browser.