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

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