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
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Radim Vansa
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
39#include <assert.h>
40#include <async.h>
41#include <malloc.h>
42#include <mem.h>
43#include <stdio.h>
44#include <byteorder.h>
45#include <str.h>
46#include <errno.h>
47#include <ipc/nil.h>
48#include <ipc/net.h>
49#include <ipc/services.h>
50#include <net/modules.h>
51#include <net_checksum.h>
52#include <ethernet_lsap.h>
53#include <ethernet_protocols.h>
54#include <protocol_map.h>
55#include <net/device.h>
56#include <net_interface.h>
57#include <il_remote.h>
58#include <adt/measured_strings.h>
59#include <packet_client.h>
60#include <packet_remote.h>
61#include <device/nic.h>
62#include <nil_skel.h>
63#include "eth.h"
64
65/** The module name. */
66#define NAME "eth"
67
68/** Reserved packet prefix length. */
69#define ETH_PREFIX \
70 (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + \
71 sizeof(eth_header_snap_t))
72
73/** Reserved packet suffix length. */
74#define ETH_SUFFIX (sizeof(eth_fcs_t))
75
76/** Maximum packet content length. */
77#define ETH_MAX_CONTENT 1500u
78
79/** Minimum packet content length. */
80#define ETH_MIN_CONTENT 46u
81
82/** Maximum tagged packet content length. */
83#define ETH_MAX_TAGGED_CONTENT(flags) \
84 (ETH_MAX_CONTENT - \
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))
88
89/** Minimum tagged packet content length. */
90#define ETH_MIN_TAGGED_CONTENT(flags) \
91 (ETH_MIN_CONTENT - \
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))
95
96/** Dummy flag shift value. */
97#define ETH_DUMMY_SHIFT 0
98
99/** Mode flag shift value. */
100#define ETH_MODE_SHIFT 1
101
102/** Dummy device flag.
103 * Preamble and FCS are mandatory part of the packets.
104 */
105#define ETH_DUMMY (1 << ETH_DUMMY_SHIFT)
106
107/** Returns the dummy flag.
108 * @see ETH_DUMMY
109 */
110#define IS_DUMMY(flags) ((flags) & ETH_DUMMY)
111
112/** Device mode flags.
113 * @see ETH_DIX
114 * @see ETH_8023_2_LSAP
115 * @see ETH_8023_2_SNAP
116 */
117#define ETH_MODE_MASK (3 << ETH_MODE_SHIFT)
118
119/** DIX Ethernet mode flag. */
120#define ETH_DIX (1 << ETH_MODE_SHIFT)
121
122/** Return whether the DIX Ethernet mode flag is set.
123 *
124 * @param[in] flags Ethernet flags.
125 * @see ETH_DIX
126 *
127 */
128#define IS_DIX(flags) (((flags) & ETH_MODE_MASK) == ETH_DIX)
129
130/** 802.3 + 802.2 + LSAP mode flag. */
131#define ETH_8023_2_LSAP (2 << ETH_MODE_SHIFT)
132
133/** Return whether the 802.3 + 802.2 + LSAP mode flag is set.
134 *
135 * @param[in] flags Ethernet flags.
136 * @see ETH_8023_2_LSAP
137 *
138 */
139#define IS_8023_2_LSAP(flags) (((flags) & ETH_MODE_MASK) == ETH_8023_2_LSAP)
140
141/** 802.3 + 802.2 + LSAP + SNAP mode flag. */
142#define ETH_8023_2_SNAP (3 << ETH_MODE_SHIFT)
143
144/** Return whether the 802.3 + 802.2 + LSAP + SNAP mode flag is set.
145 *
146 * @param[in] flags Ethernet flags.
147 * @see ETH_8023_2_SNAP
148 *
149 */
150#define IS_8023_2_SNAP(flags) (((flags) & ETH_MODE_MASK) == ETH_8023_2_SNAP)
151
152/** Type definition of the ethernet address type.
153 * @see eth_addr_type
154 */
155typedef enum eth_addr_type eth_addr_type_t;
156
157/** Ethernet address type. */
158enum eth_addr_type {
159 /** Local address. */
160 ETH_LOCAL_ADDR,
161 /** Broadcast address. */
162 ETH_BROADCAST_ADDR
163};
164
165/** Ethernet module global data. */
166eth_globals_t eth_globals;
167
168DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t);
169INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
170
171int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
172{
173 int index;
174 eth_proto_t *proto;
175
176 fibril_rwlock_read_lock(&eth_globals.protos_lock);
177 for (index = eth_protos_count(&eth_globals.protos) - 1; index >= 0;
178 index--) {
179 proto = eth_protos_get_index(&eth_globals.protos, index);
180 if ((proto) && (proto->sess)) {
181 il_device_state_msg(proto->sess, device_id, state,
182 proto->service);
183 }
184 }
185 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
186
187 return EOK;
188}
189
190int nil_initialize(async_sess_t *sess)
191{
192 int rc;
193
194 fibril_rwlock_initialize(&eth_globals.devices_lock);
195 fibril_rwlock_initialize(&eth_globals.protos_lock);
196
197 fibril_rwlock_write_lock(&eth_globals.devices_lock);
198 fibril_rwlock_write_lock(&eth_globals.protos_lock);
199
200 eth_globals.net_sess = sess;
201 memcpy(eth_globals.broadcast_addr, "\xFF\xFF\xFF\xFF\xFF\xFF",
202 ETH_ADDR);
203
204 rc = eth_devices_initialize(&eth_globals.devices);
205 if (rc != EOK) {
206 free(eth_globals.broadcast_addr);
207 goto out;
208 }
209
210 rc = eth_protos_initialize(&eth_globals.protos);
211 if (rc != EOK) {
212 free(eth_globals.broadcast_addr);
213 eth_devices_destroy(&eth_globals.devices, free);
214 }
215
216out:
217 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
218 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
219
220 return rc;
221}
222
223/** Register new device or updates the MTU of an existing one.
224 *
225 * Determine the device local hardware address.
226 *
227 * @param[in] device_id New device identifier.
228 * @param[in] handle Device driver handle.
229 * @param[in] mtu Device maximum transmission unit.
230 *
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.
234 *
235 */
236static int eth_device_message(nic_device_id_t device_id, devman_handle_t handle,
237 size_t mtu)
238{
239 eth_device_t *device;
240 int index;
241 measured_string_t names[2] = {
242 {
243 (uint8_t *) "ETH_MODE",
244 8
245 },
246 {
247 (uint8_t *) "ETH_DUMMY",
248 9
249 }
250 };
251 measured_string_t *configuration;
252 size_t count = sizeof(names) / sizeof(measured_string_t);
253 uint8_t *data;
254 eth_proto_t *proto;
255 int rc;
256
257 fibril_rwlock_write_lock(&eth_globals.devices_lock);
258 /* An existing device? */
259 device = eth_devices_find(&eth_globals.devices, device_id);
260 if (device) {
261 if (device->handle != handle) {
262 printf("Device %d already exists\n", device->device_id);
263 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
264 return EEXIST;
265 }
266
267 /* Update mtu */
268 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
269 device->mtu = mtu;
270 else
271 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
272
273 printf("Device %d already exists:\tMTU\t= %zu\n",
274 device->device_id, device->mtu);
275 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
276
277 /* Notify all upper layer modules */
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);
283 if (proto->sess) {
284 il_mtu_changed_msg(proto->sess,
285 device->device_id, device->mtu,
286 proto->service);
287 }
288 }
289
290 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
291 return EOK;
292 }
293
294 /* Create a new device */
295 device = (eth_device_t *) malloc(sizeof(eth_device_t));
296 if (!device)
297 return ENOMEM;
298
299 device->device_id = device_id;
300 device->handle = handle;
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];
308 rc = net_get_device_conf_req(eth_globals.net_sess, device->device_id,
309 &configuration, count, &data);
310 if (rc != EOK) {
311 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
312 free(device);
313 return rc;
314 }
315
316 if (configuration) {
317 if (!str_lcmp((char *) configuration[0].value, "DIX",
318 configuration[0].length)) {
319 device->flags |= ETH_DIX;
320 } else if(!str_lcmp((char *) configuration[0].value, "8023_2_LSAP",
321 configuration[0].length)) {
322 device->flags |= ETH_8023_2_LSAP;
323 } else {
324 device->flags |= ETH_8023_2_SNAP;
325 }
326
327 if (configuration[1].value &&
328 (configuration[1].value[0] == 'y')) {
329 device->flags |= ETH_DUMMY;
330 }
331 net_free_settings(configuration, data);
332 } else {
333 device->flags |= ETH_8023_2_SNAP;
334 }
335
336 /* Bind the device driver */
337 device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
338 IPC_FLAG_BLOCKING);
339 if (device->sess == NULL) {
340 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
341 free(device);
342 return ENOENT;
343 }
344
345 nic_connect_to_nil(device->sess, SERVICE_ETHERNET, device_id);
346
347 /* Get hardware address */
348 rc = nic_get_address(device->sess, &device->addr);
349 if (rc != EOK) {
350 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
351 free(device);
352 return rc;
353 }
354
355 /* Add to the cache */
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
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);
368
369 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
370 return EOK;
371}
372
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.
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.
383 */
384static eth_proto_t *eth_process_packet(int flags, packet_t *packet)
385{
386 eth_header_snap_t *header;
387 size_t length;
388 eth_type_t type;
389 size_t prefix;
390 size_t suffix;
391 eth_fcs_t *fcs;
392 uint8_t *data;
393 int rc;
394
395 length = packet_get_data_length(packet);
396
397 if (IS_DUMMY(flags))
398 packet_trim(packet, sizeof(eth_preamble_t), 0);
399 if (length < sizeof(eth_header_t) + ETH_MIN_CONTENT +
400 (IS_DUMMY(flags) ? ETH_SUFFIX : 0))
401 return NULL;
402
403 data = packet_get_data(packet);
404 header = (eth_header_snap_t *) data;
405 type = ntohs(header->header.ethertype);
406
407 if (type >= ETH_MIN_PROTO) {
408 /* DIX Ethernet */
409 prefix = sizeof(eth_header_t);
410 suffix = 0;
411 fcs = (eth_fcs_t *) data + length - sizeof(eth_fcs_t);
412 length -= sizeof(eth_fcs_t);
413 } else if (type <= ETH_MAX_CONTENT) {
414 /* Translate "LSAP" values */
415 if ((header->lsap.dsap == ETH_LSAP_GLSAP) &&
416 (header->lsap.ssap == ETH_LSAP_GLSAP)) {
417 /* Raw packet -- discard */
418 return NULL;
419 } else if ((header->lsap.dsap == ETH_LSAP_SNAP) &&
420 (header->lsap.ssap == ETH_LSAP_SNAP)) {
421 /*
422 * IEEE 802.3 + 802.2 + LSAP + SNAP
423 * organization code not supported
424 */
425 type = ntohs(header->snap.ethertype);
426 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t) +
427 sizeof(eth_header_snap_t);
428 } else {
429 /* IEEE 802.3 + 802.2 LSAP */
430 type = lsap_map(header->lsap.dsap);
431 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t);
432 }
433
434 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0U;
435 fcs = (eth_fcs_t *) data + prefix + type + suffix;
436 suffix += length - prefix - type;
437 length = prefix + type + suffix;
438 } else {
439 /* Invalid length/type, should not occur */
440 return NULL;
441 }
442
443 if (IS_DUMMY(flags)) {
444 if (~compute_crc32(~0U, data, length * 8) != ntohl(*fcs))
445 return NULL;
446 suffix += sizeof(eth_fcs_t);
447 }
448
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)
456 return NULL;
457
458 return eth_protos_find(&eth_globals.protos, type);
459}
460
461int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet)
462{
463 eth_proto_t *proto;
464 packet_t *next;
465 eth_device_t *device;
466 int flags;
467
468 fibril_rwlock_read_lock(&eth_globals.devices_lock);
469 device = eth_devices_find(&eth_globals.devices, device_id);
470 if (!device) {
471 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
472 return ENOENT;
473 }
474
475 flags = device->flags;
476 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
477 fibril_rwlock_read_lock(&eth_globals.protos_lock);
478
479 do {
480 next = pq_detach(packet);
481 proto = eth_process_packet(flags, packet);
482 if (proto) {
483 il_received_msg(proto->sess, device_id, packet,
484 proto->service);
485 } else {
486 /* Drop invalid/unknown */
487 pq_release_remote(eth_globals.net_sess,
488 packet_get_id(packet));
489 }
490 packet = next;
491 } while (packet);
492
493 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
494 return EOK;
495}
496
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.
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.
507 */
508static int eth_packet_space_message(nic_device_id_t device_id, size_t *addr_len,
509 size_t *prefix, size_t *content, size_t *suffix)
510{
511 eth_device_t *device;
512
513 if (!addr_len || !prefix || !content || !suffix)
514 return EBADMEM;
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 *content = device->mtu;
524 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
525
526 *addr_len = ETH_ADDR;
527 *prefix = ETH_PREFIX;
528 *suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
529
530 return EOK;
531}
532
533/** Send the device hardware address.
534 *
535 * @param[in] device_id The device identifier.
536 * @param[in] type Type of the desired address.
537 * @return EOK on success.
538 * @return EBADMEM if the address parameter is NULL.
539 * @return ENOENT if there no such device.
540 */
541static int eth_addr_message(nic_device_id_t device_id, eth_addr_type_t type)
542{
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 {
551 fibril_rwlock_read_lock(&eth_globals.devices_lock);
552 device = eth_devices_find(&eth_globals.devices, device_id);
553 if (!device) {
554 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
555 return ENOENT;
556 }
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;
571 }
572
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;
583}
584
585/** Register receiving module service.
586 *
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.
595 *
596 */
597static int eth_register_message(services_t service, async_sess_t *sess)
598{
599 eth_proto_t *proto;
600 int protocol;
601 int index;
602
603 protocol = protocol_map(SERVICE_ETHERNET, service);
604 if (!protocol)
605 return ENOENT;
606
607 fibril_rwlock_write_lock(&eth_globals.protos_lock);
608 proto = eth_protos_find(&eth_globals.protos, protocol);
609 if (proto) {
610 proto->sess = sess;
611 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
612 return EOK;
613 } else {
614 proto = (eth_proto_t *) malloc(sizeof(eth_proto_t));
615 if (!proto) {
616 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
617 return ENOMEM;
618 }
619
620 proto->service = service;
621 proto->protocol = protocol;
622 proto->sess = sess;
623
624 index = eth_protos_add(&eth_globals.protos, protocol, proto);
625 if (index < 0) {
626 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
627 free(proto);
628 return index;
629 }
630 }
631
632 printf("%s: Protocol registered (protocol: %d, service: %#x)\n",
633 NAME, proto->protocol, proto->service);
634
635 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
636 return EOK;
637}
638
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.
646 * @return EOK on success.
647 * @return EINVAL if the packet addresses length is not long
648 * enough.
649 * @return EINVAL if the packet is bigger than the device MTU.
650 * @return ENOMEM if there is not enough memory in the packet.
651 */
652static int
653eth_prepare_packet(int flags, packet_t *packet, uint8_t *src_addr, int ethertype,
654 size_t mtu)
655{
656 eth_header_snap_t *header;
657 eth_header_lsap_t *header_lsap;
658 eth_header_t *header_dix;
659 eth_fcs_t *fcs;
660 uint8_t *src;
661 uint8_t *dest;
662 size_t length;
663 int i;
664 void *padding;
665 eth_preamble_t *preamble;
666
667 i = packet_get_addr(packet, &src, &dest);
668 if (i < 0)
669 return i;
670
671 if (i != ETH_ADDR)
672 return EINVAL;
673
674 for (i = 0; i < ETH_ADDR; i++) {
675 if (src[i]) {
676 src_addr = src;
677 break;
678 }
679 }
680
681 length = packet_get_data_length(packet);
682 if (length > mtu)
683 return EINVAL;
684
685 if (length < ETH_MIN_TAGGED_CONTENT(flags)) {
686 padding = packet_suffix(packet,
687 ETH_MIN_TAGGED_CONTENT(flags) - length);
688 if (!padding)
689 return ENOMEM;
690
691 bzero(padding, ETH_MIN_TAGGED_CONTENT(flags) - length);
692 }
693
694 if (IS_DIX(flags)) {
695 header_dix = PACKET_PREFIX(packet, eth_header_t);
696 if (!header_dix)
697 return ENOMEM;
698
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];
703 } else if (IS_8023_2_LSAP(flags)) {
704 header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
705 if (!header_lsap)
706 return ENOMEM;
707
708 header_lsap->header.ethertype = htons(length +
709 sizeof(eth_header_lsap_t));
710 header_lsap->lsap.dsap = lsap_unmap(ntohs(ethertype));
711 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
712 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
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];
716 } else if (IS_8023_2_SNAP(flags)) {
717 header = PACKET_PREFIX(packet, eth_header_snap_t);
718 if (!header)
719 return ENOMEM;
720
721 header->header.ethertype = htons(length +
722 sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t));
723 header->lsap.dsap = (uint16_t) ETH_LSAP_SNAP;
724 header->lsap.ssap = header->lsap.dsap;
725 header->lsap.ctrl = IEEE_8023_2_UI;
726
727 for (i = 0; i < 3; i++)
728 header->snap.protocol[i] = 0;
729
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];
734 }
735
736 if (IS_DUMMY(flags)) {
737 preamble = PACKET_PREFIX(packet, eth_preamble_t);
738 if (!preamble)
739 return ENOMEM;
740
741 for (i = 0; i < 7; i++)
742 preamble->preamble[i] = ETH_PREAMBLE;
743
744 preamble->sfd = ETH_SFD;
745
746 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
747 if (!fcs)
748 return ENOMEM;
749
750 *fcs = htonl(~compute_crc32(~0U, src, length * 8));
751 }
752
753 return EOK;
754}
755
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.
764 * @return EOK on success.
765 * @return ENOENT if there no such device.
766 * @return EINVAL if the service parameter is not known.
767 */
768static int eth_send_message(nic_device_id_t device_id, packet_t *packet,
769 services_t sender)
770{
771 eth_device_t *device;
772 packet_t *next;
773 packet_t *tmp;
774 int ethertype;
775 int rc;
776
777 ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
778 if (!ethertype) {
779 pq_release_remote(eth_globals.net_sess, packet_get_id(packet));
780 return EINVAL;
781 }
782
783 fibril_rwlock_read_lock(&eth_globals.devices_lock);
784 device = eth_devices_find(&eth_globals.devices, device_id);
785 if (!device) {
786 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
787 return ENOENT;
788 }
789
790 /* Process packet queue */
791 next = packet;
792 do {
793 rc = eth_prepare_packet(device->flags, next,
794 (uint8_t *) &device->addr.address, ethertype, device->mtu);
795 if (rc != EOK) {
796 /* Release invalid packet */
797 tmp = pq_detach(next);
798 if (next == packet)
799 packet = tmp;
800 pq_release_remote(eth_globals.net_sess,
801 packet_get_id(next));
802 next = tmp;
803 } else {
804 next = pq_next(next);
805 }
806 } while (next);
807
808 /* Send packet queue */
809 if (packet)
810 nic_send_message(device->sess, packet_get_id(packet));
811
812 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
813 return EOK;
814}
815
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
860int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
861 ipc_call_t *answer, size_t *answer_count)
862{
863 packet_t *packet;
864 size_t addrlen;
865 size_t prefix;
866 size_t suffix;
867 size_t content;
868 int rc;
869
870 *answer_count = 0;
871
872 if (!IPC_GET_IMETHOD(*call))
873 return EOK;
874
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
880 switch (IPC_GET_IMETHOD(*call)) {
881 case NET_NIL_DEVICE:
882 return eth_device_message(IPC_GET_DEVICE(*call),
883 IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
884 case NET_NIL_SEND:
885 rc = packet_translate_remote(eth_globals.net_sess, &packet,
886 IPC_GET_PACKET(*call));
887 if (rc != EOK)
888 return rc;
889
890 return eth_send_message(IPC_GET_DEVICE(*call), packet,
891 IPC_GET_SERVICE(*call));
892 case NET_NIL_PACKET_SPACE:
893 rc = eth_packet_space_message(IPC_GET_DEVICE(*call), &addrlen,
894 &prefix, &content, &suffix);
895 if (rc != EOK)
896 return rc;
897
898 IPC_SET_ADDR(*answer, addrlen);
899 IPC_SET_PREFIX(*answer, prefix);
900 IPC_SET_CONTENT(*answer, content);
901 IPC_SET_SUFFIX(*answer, suffix);
902 *answer_count = 4;
903
904 return EOK;
905 case NET_NIL_ADDR:
906 rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_LOCAL_ADDR);
907 if (rc != EOK)
908 return rc;
909
910 IPC_SET_ADDR(*answer, ETH_ADDR);
911 *answer_count = 1;
912
913 return EOK;
914 case NET_NIL_BROADCAST_ADDR:
915 rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_BROADCAST_ADDR);
916 if (rc != EOK)
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;
939 }
940
941 return ENOTSUP;
942}
943
944int main(int argc, char *argv[])
945{
946 /* Start the module */
947 return nil_module_start(SERVICE_ETHERNET);
948}
949
950/** @}
951 */
Note: See TracBrowser for help on using the repository browser.