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

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

networking stack: convert to the new async framework

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