source: mainline/uspace/srv/net/nil/eth/eth.c@ 557c7d0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 557c7d0 was 7837101, checked in by Jakub Jermar <jakub@…>, 15 years ago

Get rid of superfluous uses of CONVERT_SIZE.

  • Property mode set to 100644
File size: 25.2 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 eth
30 * @{
31 */
32
33/** @file
34 * Ethernet module implementation.
35 * @see eth.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
[2687bdb]42#include <byteorder.h>
[19f857a]43#include <str.h>
[4ef32e0c]44#include <errno.h>
[21580dd]45
46#include <ipc/ipc.h>
[514ee46]47#include <ipc/net.h>
[21580dd]48#include <ipc/services.h>
49
[c7a8442]50#include <net/modules.h>
[849ed54]51#include <net_checksum.h>
52#include <ethernet_lsap.h>
53#include <ethernet_protocols.h>
54#include <protocol_map.h>
[e526f08]55#include <net/device.h>
[849ed54]56#include <netif_interface.h>
57#include <net_interface.h>
58#include <nil_interface.h>
59#include <il_interface.h>
60#include <adt/measured_strings.h>
[0a866eeb]61#include <packet_client.h>
[14f1db0]62#include <packet_remote.h>
63#include <nil_local.h>
[21580dd]64
65#include "eth.h"
66#include "eth_header.h"
67
[6067284]68/** The module name. */
[24ab58b3]69#define NAME "eth"
[849ed54]70
[6067284]71/** Reserved packet prefix length. */
72#define ETH_PREFIX \
73 (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + \
74 sizeof(eth_header_snap_t))
[21580dd]75
[6067284]76/** Reserved packet suffix length. */
77#define ETH_SUFFIX \
78 sizeof(eth_fcs_t)
[21580dd]79
[6067284]80/** Maximum packet content length. */
[21580dd]81#define ETH_MAX_CONTENT 1500u
82
[6067284]83/** Minimum packet content length. */
[21580dd]84#define ETH_MIN_CONTENT 46u
85
[6067284]86/** Maximum tagged packet content length. */
87#define ETH_MAX_TAGGED_CONTENT(flags) \
88 (ETH_MAX_CONTENT - \
89 ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
90 sizeof(eth_header_lsap_t) : 0) - \
91 (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
92
93/** Minimum tagged packet content length. */
94#define ETH_MIN_TAGGED_CONTENT(flags) \
95 (ETH_MIN_CONTENT - \
96 ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
97 sizeof(eth_header_lsap_t) : 0) - \
98 (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
99
100/** Dummy flag shift value. */
[21580dd]101#define ETH_DUMMY_SHIFT 0
102
[6067284]103/** Mode flag shift value. */
[21580dd]104#define ETH_MODE_SHIFT 1
105
106/** Dummy device flag.
[6067284]107 * Preamble and FCS are mandatory part of the packets.
[21580dd]108 */
[6067284]109#define ETH_DUMMY (1 << ETH_DUMMY_SHIFT)
[21580dd]110
111/** Returns the dummy flag.
[6067284]112 * @see ETH_DUMMY
[21580dd]113 */
[6067284]114#define IS_DUMMY(flags) ((flags) & ETH_DUMMY)
[21580dd]115
116/** Device mode flags.
[6067284]117 * @see ETH_DIX
118 * @see ETH_8023_2_LSAP
119 * @see ETH_8023_2_SNAP
[21580dd]120 */
[6067284]121#define ETH_MODE_MASK (3 << ETH_MODE_SHIFT)
[21580dd]122
[6067284]123/** DIX Ethernet mode flag. */
124#define ETH_DIX (1 << ETH_MODE_SHIFT)
[21580dd]125
126/** Returns whether the DIX Ethernet mode flag is set.
[6067284]127 *
128 * @param[in] flags The ethernet flags.
129 * @see ETH_DIX
[21580dd]130 */
[6067284]131#define IS_DIX(flags) (((flags) & ETH_MODE_MASK) == ETH_DIX)
[21580dd]132
[6067284]133/** 802.3 + 802.2 + LSAP mode flag. */
134#define ETH_8023_2_LSAP (2 << ETH_MODE_SHIFT)
[21580dd]135
136/** Returns whether the 802.3 + 802.2 + LSAP mode flag is set.
[6067284]137 *
138 * @param[in] flags The ethernet flags.
139 * @see ETH_8023_2_LSAP
[21580dd]140 */
[6067284]141#define IS_8023_2_LSAP(flags) (((flags) & ETH_MODE_MASK) == ETH_8023_2_LSAP)
[21580dd]142
[6067284]143/** 802.3 + 802.2 + LSAP + SNAP mode flag. */
144#define ETH_8023_2_SNAP (3 << ETH_MODE_SHIFT)
[21580dd]145
146/** Returns whether the 802.3 + 802.2 + LSAP + SNAP mode flag is set.
[6067284]147 *
148 * @param[in] flags The ethernet flags.
149 * @see ETH_8023_2_SNAP
[21580dd]150 */
[6067284]151#define IS_8023_2_SNAP(flags) (((flags) & ETH_MODE_MASK) == ETH_8023_2_SNAP)
[21580dd]152
153/** Type definition of the ethernet address type.
[6067284]154 * @see eth_addr_type
[21580dd]155 */
[6067284]156typedef enum eth_addr_type eth_addr_type_t;
[21580dd]157
[6067284]158/** Ethernet address type. */
159enum eth_addr_type {
160 /** Local address. */
[21580dd]161 ETH_LOCAL_ADDR,
[6067284]162 /** Broadcast address. */
[21580dd]163 ETH_BROADCAST_ADDR
164};
165
[6067284]166/** Ethernet module global data. */
167eth_globals_t eth_globals;
[21580dd]168
[6067284]169DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t);
170INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
[21580dd]171
[6067284]172int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
173{
[aadf01e]174 int index;
[4e5c7ba]175 eth_proto_t *proto;
[21580dd]176
[aadf01e]177 fibril_rwlock_read_lock(&eth_globals.protos_lock);
[6067284]178 for (index = eth_protos_count(&eth_globals.protos) - 1; index >= 0;
179 index--) {
[aadf01e]180 proto = eth_protos_get_index(&eth_globals.protos, index);
[6067284]181 if (proto && proto->phone) {
182 il_device_state_msg(proto->phone, device_id, state,
183 proto->service);
[aadf01e]184 }
[21580dd]185 }
[aadf01e]186 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[6067284]187
[21580dd]188 return EOK;
189}
190
[6067284]191int nil_initialize(int net_phone)
192{
[4ef32e0c]193 int rc;
[21580dd]194
[aadf01e]195 fibril_rwlock_initialize(&eth_globals.devices_lock);
196 fibril_rwlock_initialize(&eth_globals.protos_lock);
[6067284]197
[aadf01e]198 fibril_rwlock_write_lock(&eth_globals.devices_lock);
199 fibril_rwlock_write_lock(&eth_globals.protos_lock);
[21580dd]200 eth_globals.net_phone = net_phone;
[fb04cba8]201
[6067284]202 eth_globals.broadcast_addr =
[7837101]203 measured_string_create_bulk("\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ADDR);
[6067284]204 if (!eth_globals.broadcast_addr) {
[4ef32e0c]205 rc = ENOMEM;
[6067284]206 goto out;
[aadf01e]207 }
[fb04cba8]208
[4ef32e0c]209 rc = eth_devices_initialize(&eth_globals.devices);
210 if (rc != EOK) {
[0a3fbc7]211 free(eth_globals.broadcast_addr);
[6067284]212 goto out;
[0a3fbc7]213 }
[fb04cba8]214
[4ef32e0c]215 rc = eth_protos_initialize(&eth_globals.protos);
216 if (rc != EOK) {
[0a3fbc7]217 free(eth_globals.broadcast_addr);
[aadf01e]218 eth_devices_destroy(&eth_globals.devices);
[0a3fbc7]219 }
[6067284]220out:
[aadf01e]221 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
222 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[6067284]223
[4ef32e0c]224 return rc;
[21580dd]225}
226
[6067284]227/** Processes IPC messages from the registered device driver modules in an
228 * infinite loop.
229 *
230 * @param[in] iid The message identifier.
231 * @param[in,out] icall The message parameters.
232 */
233static void eth_receiver(ipc_callid_t iid, ipc_call_t *icall)
234{
[46d4d9f]235 packet_t *packet;
[4ef32e0c]236 int rc;
[6067284]237
238 while (true) {
[228e490]239 switch (IPC_GET_IMETHOD(*icall)) {
[6067284]240 case NET_NIL_DEVICE_STATE:
241 nil_device_state_msg_local(0, IPC_GET_DEVICE(icall),
242 IPC_GET_STATE(icall));
243 ipc_answer_0(iid, EOK);
244 break;
245 case NET_NIL_RECEIVED:
[4ef32e0c]246 rc = packet_translate_remote(eth_globals.net_phone,
247 &packet, IPC_GET_PACKET(icall));
248 if (rc == EOK) {
249 rc = nil_received_msg_local(0,
[6067284]250 IPC_GET_DEVICE(icall), packet, 0);
251 }
[96b02eb9]252 ipc_answer_0(iid, (sysarg_t) rc);
[6067284]253 break;
254 default:
[96b02eb9]255 ipc_answer_0(iid, (sysarg_t) ENOTSUP);
[6067284]256 }
257
258 iid = async_get_call(icall);
259 }
260}
261
262/** Registers new device or updates the MTU of an existing one.
263 *
264 * Determines the device local hardware address.
265 *
266 * @param[in] device_id The new device identifier.
267 * @param[in] service The device driver service.
268 * @param[in] mtu The device maximum transmission unit.
[1bfd3d3]269 * @return EOK on success.
270 * @return EEXIST if the device with the different service exists.
271 * @return ENOMEM if there is not enough memory left.
272 * @return Other error codes as defined for the
[6067284]273 * net_get_device_conf_req() function.
[1bfd3d3]274 * @return Other error codes as defined for the
[6067284]275 * netif_bind_service() function.
[1bfd3d3]276 * @return Other error codes as defined for the
[6067284]277 * netif_get_addr_req() function.
278 */
[fb04cba8]279static int eth_device_message(device_id_t device_id, services_t service,
280 size_t mtu)
[6067284]281{
[4e5c7ba]282 eth_device_t *device;
[aadf01e]283 int index;
[6067284]284 measured_string_t names[2] = {
285 {
[03649d8]286 (char *) "ETH_MODE",
[6067284]287 8
288 },
289 {
[03649d8]290 (char *) "ETH_DUMMY",
[6067284]291 9
292 }
293 };
[4eca056]294 measured_string_t *configuration;
[aadf01e]295 size_t count = sizeof(names) / sizeof(measured_string_t);
[6067284]296 char *data;
[4e5c7ba]297 eth_proto_t *proto;
[4ef32e0c]298 int rc;
[21580dd]299
[aadf01e]300 fibril_rwlock_write_lock(&eth_globals.devices_lock);
[fb04cba8]301 /* An existing device? */
[aadf01e]302 device = eth_devices_find(&eth_globals.devices, device_id);
[6067284]303 if (device) {
304 if (device->service != service) {
[aadf01e]305 printf("Device %d already exists\n", device->device_id);
306 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]307 return EEXIST;
[aadf01e]308 }
[6067284]309
[fb04cba8]310 /* Update mtu */
[6067284]311 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
[21580dd]312 device->mtu = mtu;
[6067284]313 else
314 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
315
[7e752b2]316 printf("Device %d already exists:\tMTU\t= %zu\n",
[6067284]317 device->device_id, device->mtu);
318 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
319
[fb04cba8]320 /* Notify all upper layer modules */
[6067284]321 fibril_rwlock_read_lock(&eth_globals.protos_lock);
322 for (index = 0; index < eth_protos_count(&eth_globals.protos);
323 index++) {
324 proto = eth_protos_get_index(&eth_globals.protos,
325 index);
326 if (proto->phone) {
327 il_mtu_changed_msg(proto->phone,
328 device->device_id, device->mtu,
329 proto->service);
[21580dd]330 }
331 }
[fb04cba8]332
[6067284]333 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
334 return EOK;
335 }
336
[fb04cba8]337 /* Create a new device */
[4e5c7ba]338 device = (eth_device_t *) malloc(sizeof(eth_device_t));
[6067284]339 if (!device)
340 return ENOMEM;
341
342 device->device_id = device_id;
343 device->service = service;
344 device->flags = 0;
345 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
346 device->mtu = mtu;
347 else
348 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
349
350 configuration = &names[0];
[4ef32e0c]351 rc = net_get_device_conf_req(eth_globals.net_phone, device->device_id,
352 &configuration, count, &data);
353 if (rc != EOK) {
[6067284]354 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
355 free(device);
[4ef32e0c]356 return rc;
[6067284]357 }
[fb04cba8]358
[6067284]359 if (configuration) {
360 if (!str_lcmp(configuration[0].value, "DIX",
361 configuration[0].length)) {
362 device->flags |= ETH_DIX;
363 } else if(!str_lcmp(configuration[0].value, "8023_2_LSAP",
364 configuration[0].length)) {
365 device->flags |= ETH_8023_2_LSAP;
366 } else {
367 device->flags |= ETH_8023_2_SNAP;
[21580dd]368 }
[6067284]369
370 if (configuration[1].value &&
371 (configuration[1].value[0] == 'y')) {
372 device->flags |= ETH_DUMMY;
[21580dd]373 }
[6067284]374 net_free_settings(configuration, data);
375 } else {
376 device->flags |= ETH_8023_2_SNAP;
[21580dd]377 }
[6067284]378
[fb04cba8]379 /* Bind the device driver */
[6067284]380 device->phone = netif_bind_service(device->service, device->device_id,
381 SERVICE_ETHERNET, eth_receiver);
382 if (device->phone < 0) {
383 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
384 free(device);
385 return device->phone;
386 }
387
[fb04cba8]388 /* Get hardware address */
[4ef32e0c]389 rc = netif_get_addr_req(device->phone, device->device_id, &device->addr,
390 &device->addr_data);
391 if (rc != EOK) {
[6067284]392 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
393 free(device);
[4ef32e0c]394 return rc;
[6067284]395 }
396
[fb04cba8]397 /* Add to the cache */
[6067284]398 index = eth_devices_add(&eth_globals.devices, device->device_id,
399 device);
400 if (index < 0) {
401 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
402 free(device->addr);
403 free(device->addr_data);
404 free(device);
405 return index;
406 }
407
[7e752b2]408 printf("%s: Device registered (id: %d, service: %d: mtu: %zu, "
[6067284]409 "mac: %x:%x:%x:%x:%x:%x, flags: 0x%x)\n",
410 NAME, device->device_id, device->service, device->mtu,
411 device->addr_data[0], device->addr_data[1],
412 device->addr_data[2], device->addr_data[3],
413 device->addr_data[4], device->addr_data[5], device->flags);
414
[aadf01e]415 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]416 return EOK;
417}
418
[6067284]419/** Processes the received packet and chooses the target registered module.
420 *
421 * @param[in] flags The device flags.
422 * @param[in] packet The packet.
[1bfd3d3]423 * @return The target registered module.
424 * @return NULL if the packet is not long enough.
425 * @return NULL if the packet is too long.
426 * @return NULL if the raw ethernet protocol is used.
427 * @return NULL if the dummy device FCS checksum is invalid.
428 * @return NULL if the packet address length is not big enough.
[6067284]429 */
[46d4d9f]430static eth_proto_t *eth_process_packet(int flags, packet_t *packet)
[6067284]431{
[4e5c7ba]432 eth_header_snap_t *header;
[aadf01e]433 size_t length;
434 eth_type_t type;
435 size_t prefix;
436 size_t suffix;
[4e5c7ba]437 eth_fcs_t *fcs;
[4ef32e0c]438 uint8_t *data;
439 int rc;
[aadf01e]440
441 length = packet_get_data_length(packet);
[6067284]442
443 if (IS_DUMMY(flags))
[aadf01e]444 packet_trim(packet, sizeof(eth_preamble_t), 0);
[6067284]445 if (length < sizeof(eth_header_t) + ETH_MIN_CONTENT +
446 (IS_DUMMY(flags) ? ETH_SUFFIX : 0))
447 return NULL;
448
[aadf01e]449 data = packet_get_data(packet);
[4e5c7ba]450 header = (eth_header_snap_t *) data;
[aadf01e]451 type = ntohs(header->header.ethertype);
[6067284]452
453 if (type >= ETH_MIN_PROTO) {
[fb04cba8]454 /* DIX Ethernet */
[aadf01e]455 prefix = sizeof(eth_header_t);
[21580dd]456 suffix = 0;
[4e5c7ba]457 fcs = (eth_fcs_t *) data + length - sizeof(eth_fcs_t);
[aadf01e]458 length -= sizeof(eth_fcs_t);
[6067284]459 } else if(type <= ETH_MAX_CONTENT) {
[fb04cba8]460 /* Translate "LSAP" values */
[6067284]461 if ((header->lsap.dsap == ETH_LSAP_GLSAP) &&
462 (header->lsap.ssap == ETH_LSAP_GLSAP)) {
[fb04cba8]463 /* Raw packet -- discard */
[21580dd]464 return NULL;
[6067284]465 } else if((header->lsap.dsap == ETH_LSAP_SNAP) &&
466 (header->lsap.ssap == ETH_LSAP_SNAP)) {
[fb04cba8]467 /*
468 * IEEE 802.3 + 802.2 + LSAP + SNAP
469 * organization code not supported
470 */
[aadf01e]471 type = ntohs(header->snap.ethertype);
[6067284]472 prefix = sizeof(eth_header_t) +
473 sizeof(eth_header_lsap_t) +
474 sizeof(eth_header_snap_t);
475 } else {
[fb04cba8]476 /* IEEE 802.3 + 802.2 LSAP */
[aadf01e]477 type = lsap_map(header->lsap.dsap);
[6067284]478 prefix = sizeof(eth_header_t) +
479 sizeof(eth_header_lsap_t);
[21580dd]480 }
[fb04cba8]481
[6067284]482 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0U;
[4e5c7ba]483 fcs = (eth_fcs_t *) data + prefix + type + suffix;
[21580dd]484 suffix += length - prefix - type;
485 length = prefix + type + suffix;
[6067284]486 } else {
[fb04cba8]487 /* Invalid length/type, should not occur */
[21580dd]488 return NULL;
489 }
[6067284]490
491 if (IS_DUMMY(flags)) {
[4ef32e0c]492 if (~compute_crc32(~0U, data, length * 8) != ntohl(*fcs))
[21580dd]493 return NULL;
[aadf01e]494 suffix += sizeof(eth_fcs_t);
[21580dd]495 }
[6067284]496
[4ef32e0c]497 rc = packet_set_addr(packet, header->header.source_address,
498 header->header.destination_address, ETH_ADDR);
499 if (rc != EOK)
500 return NULL;
501
502 rc = packet_trim(packet, prefix, suffix);
503 if (rc != EOK)
[21580dd]504 return NULL;
[6067284]505
[aadf01e]506 return eth_protos_find(&eth_globals.protos, type);
[21580dd]507}
508
[fb04cba8]509int nil_received_msg_local(int nil_phone, device_id_t device_id,
[46d4d9f]510 packet_t *packet, services_t target)
[6067284]511{
[4e5c7ba]512 eth_proto_t *proto;
[46d4d9f]513 packet_t *next;
[4e5c7ba]514 eth_device_t *device;
[aadf01e]515 int flags;
[21580dd]516
[aadf01e]517 fibril_rwlock_read_lock(&eth_globals.devices_lock);
518 device = eth_devices_find(&eth_globals.devices, device_id);
[6067284]519 if (!device) {
[aadf01e]520 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]521 return ENOENT;
522 }
[fb04cba8]523
[21580dd]524 flags = device->flags;
[aadf01e]525 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[6067284]526
[aadf01e]527 fibril_rwlock_read_lock(&eth_globals.protos_lock);
[6067284]528 do {
[aadf01e]529 next = pq_detach(packet);
530 proto = eth_process_packet(flags, packet);
[6067284]531 if (proto) {
532 il_received_msg(proto->phone, device_id, packet,
533 proto->service);
534 } else {
[21580dd]535 // drop invalid/unknown
[6067284]536 pq_release_remote(eth_globals.net_phone,
537 packet_get_id(packet));
[21580dd]538 }
539 packet = next;
[6067284]540 } while(packet);
[fb04cba8]541
[aadf01e]542 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]543 return EOK;
544}
545
[6067284]546/** Returns the device packet dimensions for sending.
547 *
548 * @param[in] device_id The device identifier.
549 * @param[out] addr_len The minimum reserved address length.
550 * @param[out] prefix The minimum reserved prefix size.
551 * @param[out] content The maximum content size.
552 * @param[out] suffix The minimum reserved suffix size.
[1bfd3d3]553 * @return EOK on success.
554 * @return EBADMEM if either one of the parameters is NULL.
555 * @return ENOENT if there is no such device.
[6067284]556 */
[fb04cba8]557static int eth_packet_space_message(device_id_t device_id, size_t *addr_len,
[6067284]558 size_t *prefix, size_t *content, size_t *suffix)
559{
[4e5c7ba]560 eth_device_t *device;
[21580dd]561
[6067284]562 if (!addr_len || !prefix || !content || !suffix)
[aadf01e]563 return EBADMEM;
[6067284]564
[aadf01e]565 fibril_rwlock_read_lock(&eth_globals.devices_lock);
566 device = eth_devices_find(&eth_globals.devices, device_id);
[6067284]567 if (!device) {
[aadf01e]568 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]569 return ENOENT;
570 }
[fb04cba8]571
[aadf01e]572 *content = device->mtu;
573 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[6067284]574
[aadf01e]575 *addr_len = ETH_ADDR;
576 *prefix = ETH_PREFIX;
577 *suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
[fb04cba8]578
[21580dd]579 return EOK;
580}
581
[6067284]582/** Returns the device hardware address.
583 *
584 * @param[in] device_id The device identifier.
585 * @param[in] type Type of the desired address.
586 * @param[out] address The device hardware address.
[1bfd3d3]587 * @return EOK on success.
588 * @return EBADMEM if the address parameter is NULL.
589 * @return ENOENT if there no such device.
[6067284]590 */
[fb04cba8]591static int eth_addr_message(device_id_t device_id, eth_addr_type_t type,
[4eca056]592 measured_string_t **address)
[6067284]593{
[4e5c7ba]594 eth_device_t *device;
[21580dd]595
[6067284]596 if (!address)
[aadf01e]597 return EBADMEM;
[6067284]598
599 if (type == ETH_BROADCAST_ADDR) {
[aadf01e]600 *address = eth_globals.broadcast_addr;
[6067284]601 } else {
[aadf01e]602 fibril_rwlock_read_lock(&eth_globals.devices_lock);
603 device = eth_devices_find(&eth_globals.devices, device_id);
[6067284]604 if (!device) {
[aadf01e]605 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]606 return ENOENT;
607 }
[aadf01e]608 *address = device->addr;
609 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]610 }
[6067284]611
[aadf01e]612 return (*address) ? EOK : ENOENT;
[21580dd]613}
614
[6067284]615/** Registers receiving module service.
616 *
617 * Passes received packets for this service.
618 *
619 * @param[in] service The module service.
620 * @param[in] phone The service phone.
[1bfd3d3]621 * @return EOK on success.
622 * @return ENOENT if the service is not known.
623 * @return ENOMEM if there is not enough memory left.
[6067284]624 */
625static int eth_register_message(services_t service, int phone)
626{
[4e5c7ba]627 eth_proto_t *proto;
[aadf01e]628 int protocol;
629 int index;
[21580dd]630
[aadf01e]631 protocol = protocol_map(SERVICE_ETHERNET, service);
[6067284]632 if (!protocol)
[aadf01e]633 return ENOENT;
[6067284]634
[aadf01e]635 fibril_rwlock_write_lock(&eth_globals.protos_lock);
636 proto = eth_protos_find(&eth_globals.protos, protocol);
[6067284]637 if (proto) {
[21580dd]638 proto->phone = phone;
[aadf01e]639 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]640 return EOK;
[6067284]641 } else {
[4e5c7ba]642 proto = (eth_proto_t *) malloc(sizeof(eth_proto_t));
[6067284]643 if (!proto) {
[aadf01e]644 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]645 return ENOMEM;
646 }
[fb04cba8]647
[21580dd]648 proto->service = service;
649 proto->protocol = protocol;
650 proto->phone = phone;
[fb04cba8]651
[aadf01e]652 index = eth_protos_add(&eth_globals.protos, protocol, proto);
[6067284]653 if (index < 0) {
[aadf01e]654 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
655 free(proto);
[21580dd]656 return index;
657 }
658 }
[24ab58b3]659
[6067284]660 printf("%s: Protocol registered (protocol: %d, service: %d, phone: "
661 "%d)\n", NAME, proto->protocol, proto->service, proto->phone);
[24ab58b3]662
[aadf01e]663 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]664 return EOK;
665}
666
[6067284]667/** Prepares the packet for sending.
668 *
669 * @param[in] flags The device flags.
670 * @param[in] packet The packet.
671 * @param[in] src_addr The source hardware address.
672 * @param[in] ethertype The ethernet protocol type.
673 * @param[in] mtu The device maximum transmission unit.
[1bfd3d3]674 * @return EOK on success.
675 * @return EINVAL if the packet addresses length is not long
[6067284]676 * enough.
[1bfd3d3]677 * @return EINVAL if the packet is bigger than the device MTU.
678 * @return ENOMEM if there is not enough memory in the packet.
[6067284]679 */
680static int
[46d4d9f]681eth_prepare_packet(int flags, packet_t *packet, uint8_t *src_addr, int ethertype,
[6067284]682 size_t mtu)
683{
[4e5c7ba]684 eth_header_snap_t *header;
685 eth_header_lsap_t *header_lsap;
686 eth_header_t *header_dix;
687 eth_fcs_t *fcs;
[6067284]688 uint8_t *src;
689 uint8_t *dest;
[aadf01e]690 size_t length;
691 int i;
[6067284]692 void *padding;
[4e5c7ba]693 eth_preamble_t *preamble;
[aadf01e]694
695 i = packet_get_addr(packet, &src, &dest);
[6067284]696 if (i < 0)
[aadf01e]697 return i;
[6067284]698 if (i != ETH_ADDR)
[aadf01e]699 return EINVAL;
[6067284]700
[aadf01e]701 length = packet_get_data_length(packet);
[6067284]702 if (length > mtu)
[aadf01e]703 return EINVAL;
[6067284]704
705 if (length < ETH_MIN_TAGGED_CONTENT(flags)) {
706 padding = packet_suffix(packet,
707 ETH_MIN_TAGGED_CONTENT(flags) - length);
708 if (!padding)
[aadf01e]709 return ENOMEM;
[fb04cba8]710
[aadf01e]711 bzero(padding, ETH_MIN_TAGGED_CONTENT(flags) - length);
[21580dd]712 }
[6067284]713
714 if (IS_DIX(flags)) {
[aadf01e]715 header_dix = PACKET_PREFIX(packet, eth_header_t);
[6067284]716 if (!header_dix)
[aadf01e]717 return ENOMEM;
[6067284]718
[aadf01e]719 header_dix->ethertype = (uint16_t) ethertype;
720 memcpy(header_dix->source_address, src_addr, ETH_ADDR);
721 memcpy(header_dix->destination_address, dest, ETH_ADDR);
722 src = &header_dix->destination_address[0];
[6067284]723 } else if(IS_8023_2_LSAP(flags)) {
[aadf01e]724 header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
[6067284]725 if (!header_lsap)
[aadf01e]726 return ENOMEM;
[6067284]727
728 header_lsap->header.ethertype = htons(length +
729 sizeof(eth_header_lsap_t));
[aadf01e]730 header_lsap->lsap.dsap = lsap_unmap(ntohs(ethertype));
[21580dd]731 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
732 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
[aadf01e]733 memcpy(header_lsap->header.source_address, src_addr, ETH_ADDR);
734 memcpy(header_lsap->header.destination_address, dest, ETH_ADDR);
735 src = &header_lsap->header.destination_address[0];
[6067284]736 } else if(IS_8023_2_SNAP(flags)) {
[aadf01e]737 header = PACKET_PREFIX(packet, eth_header_snap_t);
[6067284]738 if (!header)
[aadf01e]739 return ENOMEM;
[6067284]740
741 header->header.ethertype = htons(length +
742 sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t));
[aadf01e]743 header->lsap.dsap = (uint16_t) ETH_LSAP_SNAP;
[21580dd]744 header->lsap.ssap = header->lsap.dsap;
745 header->lsap.ctrl = IEEE_8023_2_UI;
[6067284]746
747 for (i = 0; i < 3; ++ i)
[aadf01e]748 header->snap.protocol[i] = 0;
[6067284]749
[aadf01e]750 header->snap.ethertype = (uint16_t) ethertype;
751 memcpy(header->header.source_address, src_addr, ETH_ADDR);
752 memcpy(header->header.destination_address, dest, ETH_ADDR);
753 src = &header->header.destination_address[0];
[21580dd]754 }
[6067284]755
756 if (IS_DUMMY(flags)) {
[aadf01e]757 preamble = PACKET_PREFIX(packet, eth_preamble_t);
[6067284]758 if (!preamble)
[aadf01e]759 return ENOMEM;
[6067284]760
761 for (i = 0; i < 7; ++ i)
[aadf01e]762 preamble->preamble[i] = ETH_PREAMBLE;
[6067284]763
[80ce111]764 preamble->sfd = ETH_SFD;
[6067284]765
[aadf01e]766 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
[6067284]767 if (!fcs)
[aadf01e]768 return ENOMEM;
[6067284]769
770 *fcs = htonl(~compute_crc32(~0U, src, length * 8));
[21580dd]771 }
[6067284]772
[21580dd]773 return EOK;
774}
775
[6067284]776/** Sends the packet queue.
777 *
778 * Sends only packet successfully processed by the eth_prepare_packet()
779 * function.
780 *
781 * @param[in] device_id The device identifier.
782 * @param[in] packet The packet queue.
783 * @param[in] sender The sending module service.
[1bfd3d3]784 * @return EOK on success.
785 * @return ENOENT if there no such device.
786 * @return EINVAL if the service parameter is not known.
[6067284]787 */
[46d4d9f]788static int eth_send_message(device_id_t device_id, packet_t *packet,
[fb04cba8]789 services_t sender)
[6067284]790{
[4e5c7ba]791 eth_device_t *device;
[46d4d9f]792 packet_t *next;
793 packet_t *tmp;
[aadf01e]794 int ethertype;
[4ef32e0c]795 int rc;
[21580dd]796
[aadf01e]797 ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
[6067284]798 if (!ethertype) {
[14f1db0]799 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
[21580dd]800 return EINVAL;
801 }
[6067284]802
[aadf01e]803 fibril_rwlock_read_lock(&eth_globals.devices_lock);
804 device = eth_devices_find(&eth_globals.devices, device_id);
[6067284]805 if (!device) {
[aadf01e]806 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]807 return ENOENT;
808 }
[6067284]809
[fb04cba8]810 /* Process packet queue */
[21580dd]811 next = packet;
[6067284]812 do {
[4ef32e0c]813 rc = eth_prepare_packet(device->flags, next,
814 (uint8_t *) device->addr->value, ethertype, device->mtu);
815 if (rc != EOK) {
[fb04cba8]816 /* Release invalid packet */
[aadf01e]817 tmp = pq_detach(next);
[6067284]818 if (next == packet)
[aadf01e]819 packet = tmp;
[6067284]820 pq_release_remote(eth_globals.net_phone,
821 packet_get_id(next));
[21580dd]822 next = tmp;
[6067284]823 } else {
[aadf01e]824 next = pq_next(next);
[21580dd]825 }
[6067284]826 } while(next);
827
[fb04cba8]828 /* Send packet queue */
[6067284]829 if (packet) {
830 netif_send_msg(device->phone, device_id, packet,
831 SERVICE_ETHERNET);
[21580dd]832 }
[fb04cba8]833
[aadf01e]834 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]835 return EOK;
836}
837
[fb04cba8]838int nil_message_standalone(const char *name, ipc_callid_t callid,
839 ipc_call_t *call, ipc_call_t *answer, int *answer_count)
[24ab58b3]840{
[4eca056]841 measured_string_t *address;
[46d4d9f]842 packet_t *packet;
[e417b96]843 size_t addrlen;
844 size_t prefix;
845 size_t suffix;
846 size_t content;
[4ef32e0c]847 int rc;
[24ab58b3]848
[aadf01e]849 *answer_count = 0;
[228e490]850 switch (IPC_GET_IMETHOD(*call)) {
[6067284]851 case IPC_M_PHONE_HUNGUP:
852 return EOK;
853
854 case NET_NIL_DEVICE:
855 return eth_device_message(IPC_GET_DEVICE(call),
856 IPC_GET_SERVICE(call), IPC_GET_MTU(call));
857 case NET_NIL_SEND:
[4ef32e0c]858 rc = packet_translate_remote(eth_globals.net_phone, &packet,
859 IPC_GET_PACKET(call));
860 if (rc != EOK)
861 return rc;
[6067284]862 return eth_send_message(IPC_GET_DEVICE(call), packet,
863 IPC_GET_SERVICE(call));
864 case NET_NIL_PACKET_SPACE:
[4ef32e0c]865 rc = eth_packet_space_message(IPC_GET_DEVICE(call), &addrlen,
866 &prefix, &content, &suffix);
867 if (rc != EOK)
868 return rc;
[6067284]869 IPC_SET_ADDR(answer, addrlen);
870 IPC_SET_PREFIX(answer, prefix);
871 IPC_SET_CONTENT(answer, content);
872 IPC_SET_SUFFIX(answer, suffix);
873 *answer_count = 4;
874 return EOK;
875 case NET_NIL_ADDR:
[4ef32e0c]876 rc = eth_addr_message(IPC_GET_DEVICE(call), ETH_LOCAL_ADDR,
877 &address);
878 if (rc != EOK)
879 return rc;
[6067284]880 return measured_strings_reply(address, 1);
881 case NET_NIL_BROADCAST_ADDR:
[4ef32e0c]882 rc = eth_addr_message(IPC_GET_DEVICE(call), ETH_BROADCAST_ADDR,
883 &address);
884 if (rc != EOK)
885 return EOK;
[6067284]886 return measured_strings_reply(address, 1);
887 case IPC_M_CONNECT_TO_ME:
888 return eth_register_message(NIL_GET_PROTO(call),
889 IPC_GET_PHONE(call));
[21580dd]890 }
[24ab58b3]891
[21580dd]892 return ENOTSUP;
893}
894
[849ed54]895/** Default thread for new connections.
896 *
[6067284]897 * @param[in] iid The initial message identifier.
898 * @param[in] icall The initial message call structure.
[849ed54]899 */
[14f1db0]900static void nil_client_connection(ipc_callid_t iid, ipc_call_t *icall)
[849ed54]901{
902 /*
903 * Accept the connection
904 * - Answer the first IPC_M_CONNECT_ME_TO call.
905 */
906 ipc_answer_0(iid, EOK);
907
[6067284]908 while (true) {
[849ed54]909 ipc_call_t answer;
910 int answer_count;
911
912 /* Clear the answer structure */
913 refresh_answer(&answer, &answer_count);
914
915 /* Fetch the next message */
916 ipc_call_t call;
917 ipc_callid_t callid = async_get_call(&call);
918
919 /* Process the message */
[6067284]920 int res = nil_module_message_standalone(NAME, callid, &call,
921 &answer, &answer_count);
[849ed54]922
[6067284]923 /*
924 * End if told to either by the message or the processing
925 * result.
926 */
[228e490]927 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
[6067284]928 (res == EHANGUP))
[849ed54]929 return;
930
931 /* Answer the message */
932 answer_call(callid, res, &answer, answer_count);
933 }
934}
935
936int main(int argc, char *argv[])
937{
[4ef32e0c]938 int rc;
[849ed54]939
940 /* Start the module */
[4ef32e0c]941 rc = nil_module_start_standalone(nil_client_connection);
942 return rc;
[849ed54]943}
944
[21580dd]945/** @}
946 */
Note: See TracBrowser for help on using the repository browser.