source: mainline/uspace/srv/net/nil/eth/eth.c@ 93ebe4e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 93ebe4e was 5fe7692, checked in by Petr Koupy <petr.koupy@…>, 14 years ago

Removed side effects from map ADTs.

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