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

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

Do not leak eth_globals.broadcast_addr in case of a failure.

  • Property mode set to 100644
File size: 25.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 <err.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/** Type definition of the ethernet address type pointer.
159 * @see eth_addr_type
160 */
161typedef eth_addr_type_t *eth_addr_type_ref;
162
163/** Ethernet address type. */
164enum eth_addr_type {
165 /** Local address. */
166 ETH_LOCAL_ADDR,
167 /** Broadcast address. */
168 ETH_BROADCAST_ADDR
169};
170
171/** Ethernet module global data. */
172eth_globals_t eth_globals;
173
174DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t);
175INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
176
177int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
178{
179 int index;
180 eth_proto_ref proto;
181
182 fibril_rwlock_read_lock(&eth_globals.protos_lock);
183 for (index = eth_protos_count(&eth_globals.protos) - 1; index >= 0;
184 index--) {
185 proto = eth_protos_get_index(&eth_globals.protos, index);
186 if (proto && proto->phone) {
187 il_device_state_msg(proto->phone, device_id, state,
188 proto->service);
189 }
190 }
191 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
192
193 return EOK;
194}
195
196int nil_initialize(int net_phone)
197{
198 ERROR_DECLARE;
199
200 fibril_rwlock_initialize(&eth_globals.devices_lock);
201 fibril_rwlock_initialize(&eth_globals.protos_lock);
202
203 fibril_rwlock_write_lock(&eth_globals.devices_lock);
204 fibril_rwlock_write_lock(&eth_globals.protos_lock);
205 eth_globals.net_phone = net_phone;
206 eth_globals.broadcast_addr =
207 measured_string_create_bulk("\xFF\xFF\xFF\xFF\xFF\xFF",
208 CONVERT_SIZE(uint8_t, char, ETH_ADDR));
209 if (!eth_globals.broadcast_addr) {
210 ERROR_CODE = ENOMEM;
211 goto out;
212 }
213 if (ERROR_OCCURRED(eth_devices_initialize(&eth_globals.devices))) {
214 free(eth_globals.broadcast_addr);
215 goto out;
216 }
217 if (ERROR_OCCURRED(eth_protos_initialize(&eth_globals.protos))) {
218 free(eth_globals.broadcast_addr);
219 eth_devices_destroy(&eth_globals.devices);
220 }
221out:
222 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
223 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
224
225 return ERROR_CODE;
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 */
234static void eth_receiver(ipc_callid_t iid, ipc_call_t *icall)
235{
236 ERROR_DECLARE;
237
238 packet_t packet;
239
240 while (true) {
241 switch (IPC_GET_METHOD(*icall)) {
242 case NET_NIL_DEVICE_STATE:
243 nil_device_state_msg_local(0, IPC_GET_DEVICE(icall),
244 IPC_GET_STATE(icall));
245 ipc_answer_0(iid, EOK);
246 break;
247 case NET_NIL_RECEIVED:
248 if (ERROR_NONE(packet_translate_remote(
249 eth_globals.net_phone, &packet,
250 IPC_GET_PACKET(icall)))) {
251 ERROR_CODE = nil_received_msg_local(0,
252 IPC_GET_DEVICE(icall), packet, 0);
253 }
254 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
255 break;
256 default:
257 ipc_answer_0(iid, (ipcarg_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 * @returns EOK on success.
272 * @returns EEXIST if the device with the different service exists.
273 * @returns ENOMEM if there is not enough memory left.
274 * @returns Other error codes as defined for the
275 * net_get_device_conf_req() function.
276 * @returns Other error codes as defined for the
277 * netif_bind_service() function.
278 * @returns Other error codes as defined for the
279 * netif_get_addr_req() function.
280 */
281static int
282eth_device_message(device_id_t device_id, services_t service, size_t mtu)
283{
284 ERROR_DECLARE;
285
286 eth_device_ref device;
287 int index;
288 measured_string_t names[2] = {
289 {
290 (char *) "ETH_MODE",
291 8
292 },
293 {
294 (char *) "ETH_DUMMY",
295 9
296 }
297 };
298 measured_string_ref configuration;
299 size_t count = sizeof(names) / sizeof(measured_string_t);
300 char *data;
301 eth_proto_ref proto;
302
303 fibril_rwlock_write_lock(&eth_globals.devices_lock);
304 // an existing device?
305 device = eth_devices_find(&eth_globals.devices, device_id);
306 if (device) {
307 if (device->service != service) {
308 printf("Device %d already exists\n", device->device_id);
309 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
310 return EEXIST;
311 }
312
313 // update mtu
314 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
315 device->mtu = mtu;
316 else
317 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
318
319 printf("Device %d already exists:\tMTU\t= %d\n",
320 device->device_id, device->mtu);
321 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
322
323 // notify all upper layer modules
324 fibril_rwlock_read_lock(&eth_globals.protos_lock);
325 for (index = 0; index < eth_protos_count(&eth_globals.protos);
326 index++) {
327 proto = eth_protos_get_index(&eth_globals.protos,
328 index);
329 if (proto->phone) {
330 il_mtu_changed_msg(proto->phone,
331 device->device_id, device->mtu,
332 proto->service);
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_ref) 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 if (ERROR_OCCURRED(net_get_device_conf_req(eth_globals.net_phone,
354 device->device_id, &configuration, count, &data))) {
355 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
356 free(device);
357 return ERROR_CODE;
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 if (ERROR_OCCURRED(netif_get_addr_req(device->phone, device->device_id,
390 &device->addr, &device->addr_data))) {
391 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
392 free(device);
393 return ERROR_CODE;
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: %d, "
408 "mac: %x:%x:%x:%x:%x:%x, 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 * @returns The target registered module.
423 * @returns NULL if the packet is not long enough.
424 * @returns NULL if the packet is too long.
425 * @returns NULL if the raw ethernet protocol is used.
426 * @returns NULL if the dummy device FCS checksum is invalid.
427 * @returns NULL if the packet address length is not big enough.
428 */
429static eth_proto_ref eth_process_packet(int flags, packet_t packet)
430{
431 ERROR_DECLARE;
432
433 eth_header_snap_ref header;
434 size_t length;
435 eth_type_t type;
436 size_t prefix;
437 size_t suffix;
438 eth_fcs_ref fcs;
439 uint8_t * data;
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_ref) 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_ref) 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
464 // discard
465 return NULL;
466 } else if((header->lsap.dsap == ETH_LSAP_SNAP) &&
467 (header->lsap.ssap == ETH_LSAP_SNAP)) {
468 // IEEE 802.3 + 802.2 + LSAP + SNAP
469 // organization code not supported
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 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0U;
481 fcs = (eth_fcs_ref) data + prefix + type + suffix;
482 suffix += length - prefix - type;
483 length = prefix + type + suffix;
484 } else {
485 // invalid length/type, should not occurr
486 return NULL;
487 }
488
489 if (IS_DUMMY(flags)) {
490 if ((~compute_crc32(~0U, data, length * 8)) != ntohl(*fcs))
491 return NULL;
492 suffix += sizeof(eth_fcs_t);
493 }
494
495 if (ERROR_OCCURRED(packet_set_addr(packet,
496 header->header.source_address, header->header.destination_address,
497 ETH_ADDR)) || ERROR_OCCURRED(packet_trim(packet, prefix, suffix))) {
498 return NULL;
499 }
500
501 return eth_protos_find(&eth_globals.protos, type);
502}
503
504int
505nil_received_msg_local(int nil_phone, device_id_t device_id, packet_t packet,
506 services_t target)
507{
508 eth_proto_ref proto;
509 packet_t next;
510 eth_device_ref device;
511 int flags;
512
513 fibril_rwlock_read_lock(&eth_globals.devices_lock);
514 device = eth_devices_find(&eth_globals.devices, device_id);
515 if (!device) {
516 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
517 return ENOENT;
518 }
519 flags = device->flags;
520 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
521
522 fibril_rwlock_read_lock(&eth_globals.protos_lock);
523 do {
524 next = pq_detach(packet);
525 proto = eth_process_packet(flags, packet);
526 if (proto) {
527 il_received_msg(proto->phone, device_id, packet,
528 proto->service);
529 } else {
530 // drop invalid/unknown
531 pq_release_remote(eth_globals.net_phone,
532 packet_get_id(packet));
533 }
534 packet = next;
535 } while(packet);
536 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
537
538 return EOK;
539}
540
541/** Returns the device packet dimensions for sending.
542 *
543 * @param[in] device_id The device identifier.
544 * @param[out] addr_len The minimum reserved address length.
545 * @param[out] prefix The minimum reserved prefix size.
546 * @param[out] content The maximum content size.
547 * @param[out] suffix The minimum reserved suffix size.
548 * @returns EOK on success.
549 * @returns EBADMEM if either one of the parameters is NULL.
550 * @returns ENOENT if there is no such device.
551 */
552static int
553eth_packet_space_message(device_id_t device_id, size_t *addr_len,
554 size_t *prefix, size_t *content, size_t *suffix)
555{
556 eth_device_ref device;
557
558 if (!addr_len || !prefix || !content || !suffix)
559 return EBADMEM;
560
561 fibril_rwlock_read_lock(&eth_globals.devices_lock);
562 device = eth_devices_find(&eth_globals.devices, device_id);
563 if (!device) {
564 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
565 return ENOENT;
566 }
567 *content = device->mtu;
568 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
569
570 *addr_len = ETH_ADDR;
571 *prefix = ETH_PREFIX;
572 *suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
573 return EOK;
574}
575
576/** Returns the device hardware address.
577 *
578 * @param[in] device_id The device identifier.
579 * @param[in] type Type of the desired address.
580 * @param[out] address The device hardware address.
581 * @returns EOK on success.
582 * @returns EBADMEM if the address parameter is NULL.
583 * @returns ENOENT if there no such device.
584 */
585static int
586eth_addr_message(device_id_t device_id, eth_addr_type_t type,
587 measured_string_ref *address)
588{
589 eth_device_ref device;
590
591 if (!address)
592 return EBADMEM;
593
594 if (type == ETH_BROADCAST_ADDR) {
595 *address = eth_globals.broadcast_addr;
596 } else {
597 fibril_rwlock_read_lock(&eth_globals.devices_lock);
598 device = eth_devices_find(&eth_globals.devices, device_id);
599 if (!device) {
600 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
601 return ENOENT;
602 }
603 *address = device->addr;
604 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
605 }
606
607 return (*address) ? EOK : ENOENT;
608}
609
610/** Registers receiving module service.
611 *
612 * Passes received packets for this service.
613 *
614 * @param[in] service The module service.
615 * @param[in] phone The service phone.
616 * @returns EOK on success.
617 * @returns ENOENT if the service is not known.
618 * @returns ENOMEM if there is not enough memory left.
619 */
620static int eth_register_message(services_t service, int phone)
621{
622 eth_proto_ref proto;
623 int protocol;
624 int index;
625
626 protocol = protocol_map(SERVICE_ETHERNET, service);
627 if (!protocol)
628 return ENOENT;
629
630 fibril_rwlock_write_lock(&eth_globals.protos_lock);
631 proto = eth_protos_find(&eth_globals.protos, protocol);
632 if (proto) {
633 proto->phone = phone;
634 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
635 return EOK;
636 } else {
637 proto = (eth_proto_ref) malloc(sizeof(eth_proto_t));
638 if (!proto) {
639 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
640 return ENOMEM;
641 }
642 proto->service = service;
643 proto->protocol = protocol;
644 proto->phone = phone;
645 index = eth_protos_add(&eth_globals.protos, protocol, proto);
646 if (index < 0) {
647 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
648 free(proto);
649 return index;
650 }
651 }
652
653 printf("%s: Protocol registered (protocol: %d, service: %d, phone: "
654 "%d)\n", NAME, proto->protocol, proto->service, proto->phone);
655
656 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
657 return EOK;
658}
659
660/** Prepares the packet for sending.
661 *
662 * @param[in] flags The device flags.
663 * @param[in] packet The packet.
664 * @param[in] src_addr The source hardware address.
665 * @param[in] ethertype The ethernet protocol type.
666 * @param[in] mtu The device maximum transmission unit.
667 * @returns EOK on success.
668 * @returns EINVAL if the packet addresses length is not long
669 * enough.
670 * @returns EINVAL if the packet is bigger than the device MTU.
671 * @returns ENOMEM if there is not enough memory in the packet.
672 */
673static int
674eth_prepare_packet(int flags, packet_t packet, uint8_t *src_addr, int ethertype,
675 size_t mtu)
676{
677 eth_header_snap_ref header;
678 eth_header_lsap_ref header_lsap;
679 eth_header_ref header_dix;
680 eth_fcs_ref fcs;
681 uint8_t *src;
682 uint8_t *dest;
683 size_t length;
684 int i;
685 void *padding;
686 eth_preamble_ref preamble;
687
688 i = packet_get_addr(packet, &src, &dest);
689 if (i < 0)
690 return i;
691 if (i != ETH_ADDR)
692 return EINVAL;
693
694 length = packet_get_data_length(packet);
695 if (length > mtu)
696 return EINVAL;
697
698 if (length < ETH_MIN_TAGGED_CONTENT(flags)) {
699 padding = packet_suffix(packet,
700 ETH_MIN_TAGGED_CONTENT(flags) - length);
701 if (!padding)
702 return ENOMEM;
703 bzero(padding, ETH_MIN_TAGGED_CONTENT(flags) - length);
704 }
705
706 if (IS_DIX(flags)) {
707 header_dix = PACKET_PREFIX(packet, eth_header_t);
708 if (!header_dix)
709 return ENOMEM;
710
711 header_dix->ethertype = (uint16_t) ethertype;
712 memcpy(header_dix->source_address, src_addr, ETH_ADDR);
713 memcpy(header_dix->destination_address, dest, ETH_ADDR);
714 src = &header_dix->destination_address[0];
715 } else if(IS_8023_2_LSAP(flags)) {
716 header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
717 if (!header_lsap)
718 return ENOMEM;
719
720 header_lsap->header.ethertype = htons(length +
721 sizeof(eth_header_lsap_t));
722 header_lsap->lsap.dsap = lsap_unmap(ntohs(ethertype));
723 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
724 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
725 memcpy(header_lsap->header.source_address, src_addr, ETH_ADDR);
726 memcpy(header_lsap->header.destination_address, dest, ETH_ADDR);
727 src = &header_lsap->header.destination_address[0];
728 } else if(IS_8023_2_SNAP(flags)) {
729 header = PACKET_PREFIX(packet, eth_header_snap_t);
730 if (!header)
731 return ENOMEM;
732
733 header->header.ethertype = htons(length +
734 sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t));
735 header->lsap.dsap = (uint16_t) ETH_LSAP_SNAP;
736 header->lsap.ssap = header->lsap.dsap;
737 header->lsap.ctrl = IEEE_8023_2_UI;
738
739 for (i = 0; i < 3; ++ i)
740 header->snap.protocol[i] = 0;
741
742 header->snap.ethertype = (uint16_t) ethertype;
743 memcpy(header->header.source_address, src_addr, ETH_ADDR);
744 memcpy(header->header.destination_address, dest, ETH_ADDR);
745 src = &header->header.destination_address[0];
746 }
747
748 if (IS_DUMMY(flags)) {
749 preamble = PACKET_PREFIX(packet, eth_preamble_t);
750 if (!preamble)
751 return ENOMEM;
752
753 for (i = 0; i < 7; ++ i)
754 preamble->preamble[i] = ETH_PREAMBLE;
755
756 preamble->sfd = ETH_SFD;
757
758 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
759 if (!fcs)
760 return ENOMEM;
761
762 *fcs = htonl(~compute_crc32(~0U, src, length * 8));
763 }
764
765 return EOK;
766}
767
768/** Sends the packet queue.
769 *
770 * Sends only packet successfully processed by the eth_prepare_packet()
771 * function.
772 *
773 * @param[in] device_id The device identifier.
774 * @param[in] packet The packet queue.
775 * @param[in] sender The sending module service.
776 * @returns EOK on success.
777 * @returns ENOENT if there no such device.
778 * @returns EINVAL if the service parameter is not known.
779 */
780static int
781eth_send_message(device_id_t device_id, packet_t packet, services_t sender)
782{
783 ERROR_DECLARE;
784
785 eth_device_ref device;
786 packet_t next;
787 packet_t tmp;
788 int ethertype;
789
790 ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
791 if (!ethertype) {
792 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
793 return EINVAL;
794 }
795
796 fibril_rwlock_read_lock(&eth_globals.devices_lock);
797 device = eth_devices_find(&eth_globals.devices, device_id);
798 if (!device) {
799 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
800 return ENOENT;
801 }
802
803 // process packet queue
804 next = packet;
805 do {
806 if (ERROR_OCCURRED(eth_prepare_packet(device->flags, next,
807 (uint8_t *) device->addr->value, ethertype, device->mtu))) {
808 // release invalid packet
809 tmp = pq_detach(next);
810 if (next == packet)
811 packet = tmp;
812 pq_release_remote(eth_globals.net_phone,
813 packet_get_id(next));
814 next = tmp;
815 } else {
816 next = pq_next(next);
817 }
818 } while(next);
819
820 // send packet queue
821 if (packet) {
822 netif_send_msg(device->phone, device_id, packet,
823 SERVICE_ETHERNET);
824 }
825 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
826
827 return EOK;
828}
829
830int
831nil_message_standalone(const char *name, ipc_callid_t callid, ipc_call_t *call,
832 ipc_call_t *answer, int *answer_count)
833{
834 ERROR_DECLARE;
835
836 measured_string_ref address;
837 packet_t packet;
838 size_t addrlen;
839 size_t prefix;
840 size_t suffix;
841 size_t content;
842
843 *answer_count = 0;
844 switch (IPC_GET_METHOD(*call)) {
845 case IPC_M_PHONE_HUNGUP:
846 return EOK;
847
848 case NET_NIL_DEVICE:
849 return eth_device_message(IPC_GET_DEVICE(call),
850 IPC_GET_SERVICE(call), IPC_GET_MTU(call));
851 case NET_NIL_SEND:
852 ERROR_PROPAGATE(packet_translate_remote(eth_globals.net_phone,
853 &packet, IPC_GET_PACKET(call)));
854 return eth_send_message(IPC_GET_DEVICE(call), packet,
855 IPC_GET_SERVICE(call));
856 case NET_NIL_PACKET_SPACE:
857 ERROR_PROPAGATE(eth_packet_space_message(IPC_GET_DEVICE(call),
858 &addrlen, &prefix, &content, &suffix));
859 IPC_SET_ADDR(answer, addrlen);
860 IPC_SET_PREFIX(answer, prefix);
861 IPC_SET_CONTENT(answer, content);
862 IPC_SET_SUFFIX(answer, suffix);
863 *answer_count = 4;
864 return EOK;
865 case NET_NIL_ADDR:
866 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call),
867 ETH_LOCAL_ADDR, &address));
868 return measured_strings_reply(address, 1);
869 case NET_NIL_BROADCAST_ADDR:
870 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call),
871 ETH_BROADCAST_ADDR, &address));
872 return measured_strings_reply(address, 1);
873 case IPC_M_CONNECT_TO_ME:
874 return eth_register_message(NIL_GET_PROTO(call),
875 IPC_GET_PHONE(call));
876 }
877
878 return ENOTSUP;
879}
880
881/** Default thread for new connections.
882 *
883 * @param[in] iid The initial message identifier.
884 * @param[in] icall The initial message call structure.
885 *
886 */
887static void nil_client_connection(ipc_callid_t iid, ipc_call_t *icall)
888{
889 /*
890 * Accept the connection
891 * - Answer the first IPC_M_CONNECT_ME_TO call.
892 */
893 ipc_answer_0(iid, EOK);
894
895 while (true) {
896 ipc_call_t answer;
897 int answer_count;
898
899 /* Clear the answer structure */
900 refresh_answer(&answer, &answer_count);
901
902 /* Fetch the next message */
903 ipc_call_t call;
904 ipc_callid_t callid = async_get_call(&call);
905
906 /* Process the message */
907 int res = nil_module_message_standalone(NAME, callid, &call,
908 &answer, &answer_count);
909
910 /*
911 * End if told to either by the message or the processing
912 * result.
913 */
914 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
915 (res == EHANGUP))
916 return;
917
918 /* Answer the message */
919 answer_call(callid, res, &answer, answer_count);
920 }
921}
922
923int main(int argc, char *argv[])
924{
925 ERROR_DECLARE;
926
927 /* Start the module */
928 ERROR_PROPAGATE(nil_module_start_standalone(nil_client_connection));
929 return EOK;
930}
931
932/** @}
933 */
Note: See TracBrowser for help on using the repository browser.