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
RevLine 
[21580dd]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>
[19f857a]42#include <str.h>
[21580dd]43
44#include <ipc/ipc.h>
45#include <ipc/services.h>
46
[849ed54]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>
[21580dd]62
63#include "eth.h"
64#include "eth_header.h"
65
[849ed54]66/** The module name.
67 */
68#define NAME "Ethernet protocol"
69
[21580dd]70/** Reserved packet prefix length.
71 */
[aadf01e]72#define ETH_PREFIX (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t))
[21580dd]73
74/** Reserved packet suffix length.
75 */
[aadf01e]76#define ETH_SUFFIX sizeof(eth_fcs_t)
[21580dd]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 */
[aadf01e]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))
[21580dd]89
90/** Minimum tagged packet content length.
91 */
[aadf01e]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))
[21580dd]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 */
[aadf01e]105#define ETH_DUMMY (1 << ETH_DUMMY_SHIFT)
[21580dd]106
107/** Returns the dummy flag.
108 * @see ETH_DUMMY
109 */
[aadf01e]110#define IS_DUMMY(flags) ((flags) &ETH_DUMMY)
[21580dd]111
112/** Device mode flags.
113 * @see ETH_DIX
114 * @see ETH_8023_2_LSAP
115 * @see ETH_8023_2_SNAP
116 */
[aadf01e]117#define ETH_MODE_MASK (3 << ETH_MODE_SHIFT)
[21580dd]118
119/** DIX Ethernet mode flag.
120 */
[aadf01e]121#define ETH_DIX (1 << ETH_MODE_SHIFT)
[21580dd]122
123/** Returns whether the DIX Ethernet mode flag is set.
124 * @param[in] flags The ethernet flags.
125 * @see ETH_DIX
126 */
[aadf01e]127#define IS_DIX(flags) (((flags) &ETH_MODE_MASK) == ETH_DIX)
[21580dd]128
129/** 802.3 + 802.2 + LSAP mode flag.
130 */
[aadf01e]131#define ETH_8023_2_LSAP (2 << ETH_MODE_SHIFT)
[21580dd]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 */
[aadf01e]137#define IS_8023_2_LSAP(flags) (((flags) &ETH_MODE_MASK) == ETH_8023_2_LSAP)
[21580dd]138
139/** 802.3 + 802.2 + LSAP + SNAP mode flag.
140 */
[aadf01e]141#define ETH_8023_2_SNAP (3 << ETH_MODE_SHIFT)
[21580dd]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 */
[aadf01e]147#define IS_8023_2_SNAP(flags) (((flags) &ETH_MODE_MASK) == ETH_8023_2_SNAP)
[21580dd]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 */
[aadf01e]182void eth_receiver(ipc_callid_t iid, ipc_call_t * icall);
[21580dd]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 */
[aadf01e]196int eth_device_message(device_id_t device_id, services_t service, size_t mtu);
[21580dd]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 */
[aadf01e]206int eth_register_message(services_t service, int phone);
[21580dd]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 */
[aadf01e]218int eth_packet_space_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix);
[21580dd]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 */
[aadf01e]228int eth_addr_message(device_id_t device_id, eth_addr_type_t type, measured_string_ref * address);
[21580dd]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 */
[aadf01e]239int eth_send_message(device_id_t device_id, packet_t packet, services_t sender);
[21580dd]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 */
[aadf01e]253eth_proto_ref eth_process_packet(int flags, packet_t packet);
[21580dd]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 */
[aadf01e]266int eth_prepare_packet(int flags, packet_t packet, uint8_t * src_addr, int ethertype, size_t mtu);
[21580dd]267
[aadf01e]268DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t)
[21580dd]269
[aadf01e]270INT_MAP_IMPLEMENT(eth_protos, eth_proto_t)
[21580dd]271
[aadf01e]272int nil_device_state_msg(int nil_phone, device_id_t device_id, int state){
273 int index;
274 eth_proto_ref proto;
[21580dd]275
[aadf01e]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 }
[21580dd]282 }
[aadf01e]283 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]284 return EOK;
285}
286
[aadf01e]287int nil_initialize(int net_phone){
[21580dd]288 ERROR_DECLARE;
289
[aadf01e]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);
[21580dd]294 eth_globals.net_phone = net_phone;
[aadf01e]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);
[21580dd]302 return ERROR_CODE;
303 }
[aadf01e]304 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
305 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]306 return EOK;
307}
308
[aadf01e]309int eth_device_message(device_id_t device_id, services_t service, size_t mtu){
[21580dd]310 ERROR_DECLARE;
311
[aadf01e]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;
[21580dd]319
[aadf01e]320 fibril_rwlock_write_lock(&eth_globals.devices_lock);
[21580dd]321 // an existing device?
[aadf01e]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);
[21580dd]327 return EEXIST;
328 }else{
329 // update mtu
[aadf01e]330 if((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags))){
[21580dd]331 device->mtu = mtu;
332 }else{
[aadf01e]333 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
[21580dd]334 }
[aadf01e]335 printf("Device %d already exists:\tMTU\t= %d\n", device->device_id, device->mtu);
336 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]337 // notify all upper layer modules
[aadf01e]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);
[21580dd]343 }
344 }
[aadf01e]345 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]346 return EOK;
347 }
348 }else{
349 // create a new device
[aadf01e]350 device = (eth_device_ref) malloc(sizeof(eth_device_t));
351 if(! device){
352 return ENOMEM;
353 }
[21580dd]354 device->device_id = device_id;
355 device->service = service;
356 device->flags = 0;
[aadf01e]357 if((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags))){
[21580dd]358 device->mtu = mtu;
359 }else{
[aadf01e]360 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
[21580dd]361 }
[aadf01e]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);
[21580dd]366 return ERROR_CODE;
367 }
[aadf01e]368 if(configuration){
369 if(! str_lcmp(configuration[0].value, "DIX", configuration[0].length)){
[21580dd]370 device->flags |= ETH_DIX;
[aadf01e]371 }else if(! str_lcmp(configuration[0].value, "8023_2_LSAP", configuration[0].length)){
[21580dd]372 device->flags |= ETH_8023_2_LSAP;
373 }else device->flags |= ETH_8023_2_SNAP;
[aadf01e]374 if((configuration[1].value) && (configuration[1].value[0] == 'y')){
[21580dd]375 device->flags |= ETH_DUMMY;
376 }
[aadf01e]377 net_free_settings(configuration, data);
[21580dd]378 }else{
379 device->flags |= ETH_8023_2_SNAP;
380 }
381 // bind the device driver
[aadf01e]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);
[21580dd]386 return device->phone;
387 }
388 // get hardware address
[aadf01e]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);
[21580dd]392 return ERROR_CODE;
393 }
394 // add to the cache
[aadf01e]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);
[21580dd]401 return index;
402 }
[aadf01e]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);
[21580dd]404 }
[aadf01e]405 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]406 return EOK;
407}
408
[aadf01e]409eth_proto_ref eth_process_packet(int flags, packet_t packet){
[21580dd]410 ERROR_DECLARE;
411
[aadf01e]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);
[21580dd]423 }
[aadf01e]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){
[21580dd]429 // DIX Ethernet
[aadf01e]430 prefix = sizeof(eth_header_t);
[21580dd]431 suffix = 0;
[aadf01e]432 fcs = (eth_fcs_ref) data + length - sizeof(eth_fcs_t);
433 length -= sizeof(eth_fcs_t);
434 }else if(type <= ETH_MAX_CONTENT){
[21580dd]435 // translate "LSAP" values
[aadf01e]436 if((header->lsap.dsap == ETH_LSAP_GLSAP) && (header->lsap.ssap == ETH_LSAP_GLSAP)){
[21580dd]437 // raw packet
438 // discard
439 return NULL;
[aadf01e]440 }else if((header->lsap.dsap == ETH_LSAP_SNAP) && (header->lsap.ssap == ETH_LSAP_SNAP)){
[21580dd]441 // IEEE 802.3 + 802.2 + LSAP + SNAP
442 // organization code not supported
[aadf01e]443 type = ntohs(header->snap.ethertype);
444 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t);
[21580dd]445 }else{
446 // IEEE 802.3 + 802.2 LSAP
[aadf01e]447 type = lsap_map(header->lsap.dsap);
448 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t);
[21580dd]449 }
[aadf01e]450 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0u;
451 fcs = (eth_fcs_ref) data + prefix + type + suffix;
[21580dd]452 suffix += length - prefix - type;
453 length = prefix + type + suffix;
454 }else{
455 // invalid length/type, should not occurr
456 return NULL;
457 }
[aadf01e]458 if(IS_DUMMY(flags)){
459 if((~ compute_crc32(~ 0u, data, length * 8)) != ntohl(*fcs)){
[21580dd]460 return NULL;
461 }
[aadf01e]462 suffix += sizeof(eth_fcs_t);
[21580dd]463 }
[aadf01e]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))){
[21580dd]466 return NULL;
467 }
[aadf01e]468 return eth_protos_find(&eth_globals.protos, type);
[21580dd]469}
470
[aadf01e]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;
[21580dd]476
[aadf01e]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);
[21580dd]481 return ENOENT;
482 }
483 flags = device->flags;
[aadf01e]484 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
485 fibril_rwlock_read_lock(&eth_globals.protos_lock);
[21580dd]486 do{
[aadf01e]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);
[21580dd]491 }else{
492 // drop invalid/unknown
[aadf01e]493 pq_release(eth_globals.net_phone, packet_get_id(packet));
[21580dd]494 }
495 packet = next;
[aadf01e]496 }while(packet);
497 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]498 return EOK;
499}
500
[aadf01e]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;
[21580dd]503
[aadf01e]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);
[21580dd]511 return ENOENT;
512 }
[aadf01e]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;
[21580dd]518 return EOK;
519}
520
[aadf01e]521int eth_addr_message(device_id_t device_id, eth_addr_type_t type, measured_string_ref * address){
522 eth_device_ref device;
[21580dd]523
[aadf01e]524 if(! address){
525 return EBADMEM;
526 }
527 if(type == ETH_BROADCAST_ADDR){
528 *address = eth_globals.broadcast_addr;
[21580dd]529 }else{
[aadf01e]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);
[21580dd]534 return ENOENT;
535 }
[aadf01e]536 *address = device->addr;
537 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]538 }
[aadf01e]539 return (*address) ? EOK : ENOENT;
[21580dd]540}
541
[aadf01e]542int eth_register_message(services_t service, int phone){
543 eth_proto_ref proto;
544 int protocol;
545 int index;
[21580dd]546
[aadf01e]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){
[21580dd]554 proto->phone = phone;
[aadf01e]555 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]556 return EOK;
557 }else{
[aadf01e]558 proto = (eth_proto_ref) malloc(sizeof(eth_proto_t));
559 if(! proto){
560 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]561 return ENOMEM;
562 }
563 proto->service = service;
564 proto->protocol = protocol;
565 proto->phone = phone;
[aadf01e]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);
[21580dd]570 return index;
571 }
572 }
[aadf01e]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);
[21580dd]575 return EOK;
576}
577
[aadf01e]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);
[21580dd]607 }
[aadf01e]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));
[21580dd]624 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
625 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
[aadf01e]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;
[21580dd]636 header->lsap.ssap = header->lsap.dsap;
637 header->lsap.ctrl = IEEE_8023_2_UI;
[aadf01e]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];
[21580dd]645 }
[aadf01e]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 }
[80ce111]654 preamble->sfd = ETH_SFD;
[aadf01e]655 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
656 if(! fcs){
657 return ENOMEM;
658 }
659 *fcs = htonl(~ compute_crc32(~ 0u, src, length * 8));
[21580dd]660 }
661 return EOK;
662}
663
[aadf01e]664int eth_send_message(device_id_t device_id, packet_t packet, services_t sender){
[21580dd]665 ERROR_DECLARE;
666
[aadf01e]667 eth_device_ref device;
668 packet_t next;
669 packet_t tmp;
670 int ethertype;
[21580dd]671
[aadf01e]672 ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
673 if(! ethertype){
674 pq_release(eth_globals.net_phone, packet_get_id(packet));
[21580dd]675 return EINVAL;
676 }
[aadf01e]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);
[21580dd]681 return ENOENT;
682 }
683 // process packet queue
684 next = packet;
685 do{
[aadf01e]686 if(ERROR_OCCURRED(eth_prepare_packet(device->flags, next, (uint8_t *) device->addr->value, ethertype, device->mtu))){
[21580dd]687 // release invalid packet
[aadf01e]688 tmp = pq_detach(next);
689 if(next == packet){
690 packet = tmp;
691 }
692 pq_release(eth_globals.net_phone, packet_get_id(next));
[21580dd]693 next = tmp;
694 }else{
[aadf01e]695 next = pq_next(next);
[21580dd]696 }
[aadf01e]697 }while(next);
[21580dd]698 // send packet queue
[aadf01e]699 if(packet){
700 netif_send_msg(device->phone, device_id, packet, SERVICE_ETHERNET);
[21580dd]701 }
[aadf01e]702 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]703 return EOK;
704}
705
[aadf01e]706int nil_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
[21580dd]707 ERROR_DECLARE;
708
[aadf01e]709 measured_string_ref address;
710 packet_t packet;
[e417b96]711 size_t addrlen;
712 size_t prefix;
713 size_t suffix;
714 size_t content;
[21580dd]715
[aadf01e]716// printf("message %d - %d\n", IPC_GET_METHOD(*call), NET_NIL_FIRST);
717 *answer_count = 0;
718 switch(IPC_GET_METHOD(*call)){
[21580dd]719 case IPC_M_PHONE_HUNGUP:
720 return EOK;
721 case NET_NIL_DEVICE:
[aadf01e]722 return eth_device_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), IPC_GET_MTU(call));
[21580dd]723 case NET_NIL_SEND:
[aadf01e]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));
[21580dd]726 case NET_NIL_PACKET_SPACE:
[e417b96]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);
[aadf01e]732 *answer_count = 4;
[21580dd]733 return EOK;
734 case NET_NIL_ADDR:
[aadf01e]735 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call), ETH_LOCAL_ADDR, &address));
736 return measured_strings_reply(address, 1);
[21580dd]737 case NET_NIL_BROADCAST_ADDR:
[aadf01e]738 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call), ETH_BROADCAST_ADDR, &address));
739 return measured_strings_reply(address, 1);
[21580dd]740 case IPC_M_CONNECT_TO_ME:
[aadf01e]741 return eth_register_message(NIL_GET_PROTO(call), IPC_GET_PHONE(call));
[21580dd]742 }
743 return ENOTSUP;
744}
745
[aadf01e]746void eth_receiver(ipc_callid_t iid, ipc_call_t * icall){
[21580dd]747 ERROR_DECLARE;
748
[aadf01e]749 packet_t packet;
[21580dd]750
[aadf01e]751 while(true){
752// printf("message %d - %d\n", IPC_GET_METHOD(*icall), NET_NIL_FIRST);
753 switch(IPC_GET_METHOD(*icall)){
[21580dd]754 case NET_NIL_DEVICE_STATE:
[aadf01e]755 nil_device_state_msg(0, IPC_GET_DEVICE(icall), IPC_GET_STATE(icall));
756 ipc_answer_0(iid, EOK);
[21580dd]757 break;
758 case NET_NIL_RECEIVED:
[aadf01e]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);
[21580dd]761 }
[aadf01e]762 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
[21580dd]763 break;
764 default:
[aadf01e]765 ipc_answer_0(iid, (ipcarg_t) ENOTSUP);
[21580dd]766 }
[aadf01e]767 iid = async_get_call(icall);
[21580dd]768 }
769}
770
[849ed54]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
[21580dd]839/** @}
840 */
Note: See TracBrowser for help on using the repository browser.