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

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

Do not leak the 'names' measured string values.

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