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

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

do not intermix low-level IPC methods with async framework methods

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