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

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

Integrate net_err.h into the standard library's err.h.

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