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

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

streamline internetworking layer

  • IPC method renaming

NET_IL_DEVICE → NET_IP_DEVICE
NET_IL_PACKET_SPACE → NET_IP_PACKET_SPACE
NET_IL_SEND → NET_IP_SEND

The original methods were actually not generic methods of the IL layer (used by the lower layers), but specific methods of the IP module
and used by the higher layers. The original naming was rather confusing.

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