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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 55091847 was 9934f7d, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Add extra argument to async connection handlers that can be used for passing
information from async_connect_to_me() to the handler.

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