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

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