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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 849ed54 was 849ed54, checked in by Martin Decky <martin@…>, 15 years ago

Networking work:
Split the networking stack into end-user library (libsocket) and two helper libraries (libnet and libnetif).
Don't use over-the-hand compiling and linking, but rather separation of conserns.
There might be still some issues and the non-modular networking architecture is currently broken, but this will be fixed soon.

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