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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ea28272 was 7837101, checked in by Jakub Jermar <jakub@…>, 15 years ago

Get rid of superfluous uses of CONVERT_SIZE.

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