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

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

cstyle

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