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

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

Move net_modules.[ch] to the standard library. Note that this functionality is
not directly related to networking so the next step regarding these two files
would be to somehow merge its functionality with what we already have in lib c.

  • Property mode set to 100644
File size: 25.7 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>
[2687bdb]42#include <byteorder.h>
[19f857a]43#include <str.h>
[c5b59ce]44#include <err.h>
[21580dd]45
46#include <ipc/ipc.h>
47#include <ipc/services.h>
48
[849ed54]49#include <net_messages.h>
[c7a8442]50#include <net/modules.h>
[849ed54]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>
[14f1db0]62#include <packet_remote.h>
63#include <nil_local.h>
[21580dd]64
65#include "eth.h"
66#include "eth_header.h"
67
[849ed54]68/** The module name.
69 */
[24ab58b3]70#define NAME "eth"
[849ed54]71
[21580dd]72/** Reserved packet prefix length.
73 */
[aadf01e]74#define ETH_PREFIX (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t))
[21580dd]75
76/** Reserved packet suffix length.
77 */
[aadf01e]78#define ETH_SUFFIX sizeof(eth_fcs_t)
[21580dd]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 */
[aadf01e]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))
[21580dd]91
92/** Minimum tagged packet content length.
93 */
[aadf01e]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))
[21580dd]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 */
[aadf01e]107#define ETH_DUMMY (1 << ETH_DUMMY_SHIFT)
[21580dd]108
109/** Returns the dummy flag.
110 * @see ETH_DUMMY
111 */
[aadf01e]112#define IS_DUMMY(flags) ((flags) &ETH_DUMMY)
[21580dd]113
114/** Device mode flags.
115 * @see ETH_DIX
116 * @see ETH_8023_2_LSAP
117 * @see ETH_8023_2_SNAP
118 */
[aadf01e]119#define ETH_MODE_MASK (3 << ETH_MODE_SHIFT)
[21580dd]120
121/** DIX Ethernet mode flag.
122 */
[aadf01e]123#define ETH_DIX (1 << ETH_MODE_SHIFT)
[21580dd]124
125/** Returns whether the DIX Ethernet mode flag is set.
126 * @param[in] flags The ethernet flags.
127 * @see ETH_DIX
128 */
[aadf01e]129#define IS_DIX(flags) (((flags) &ETH_MODE_MASK) == ETH_DIX)
[21580dd]130
131/** 802.3 + 802.2 + LSAP mode flag.
132 */
[aadf01e]133#define ETH_8023_2_LSAP (2 << ETH_MODE_SHIFT)
[21580dd]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 */
[aadf01e]139#define IS_8023_2_LSAP(flags) (((flags) &ETH_MODE_MASK) == ETH_8023_2_LSAP)
[21580dd]140
141/** 802.3 + 802.2 + LSAP + SNAP mode flag.
142 */
[aadf01e]143#define ETH_8023_2_SNAP (3 << ETH_MODE_SHIFT)
[21580dd]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 */
[aadf01e]149#define IS_8023_2_SNAP(flags) (((flags) &ETH_MODE_MASK) == ETH_8023_2_SNAP)
[21580dd]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 */
[aadf01e]184void eth_receiver(ipc_callid_t iid, ipc_call_t * icall);
[21580dd]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 */
[aadf01e]198int eth_device_message(device_id_t device_id, services_t service, size_t mtu);
[21580dd]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 */
[aadf01e]208int eth_register_message(services_t service, int phone);
[21580dd]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 */
[aadf01e]220int eth_packet_space_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix);
[21580dd]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 */
[aadf01e]230int eth_addr_message(device_id_t device_id, eth_addr_type_t type, measured_string_ref * address);
[21580dd]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 */
[aadf01e]241int eth_send_message(device_id_t device_id, packet_t packet, services_t sender);
[21580dd]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 */
[aadf01e]255eth_proto_ref eth_process_packet(int flags, packet_t packet);
[21580dd]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 */
[aadf01e]268int eth_prepare_packet(int flags, packet_t packet, uint8_t * src_addr, int ethertype, size_t mtu);
[21580dd]269
[aadf01e]270DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t)
[21580dd]271
[aadf01e]272INT_MAP_IMPLEMENT(eth_protos, eth_proto_t)
[21580dd]273
[14f1db0]274int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state){
[aadf01e]275 int index;
276 eth_proto_ref proto;
[21580dd]277
[aadf01e]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 }
[21580dd]284 }
[aadf01e]285 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]286 return EOK;
287}
288
[aadf01e]289int nil_initialize(int net_phone){
[21580dd]290 ERROR_DECLARE;
291
[aadf01e]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);
[21580dd]296 eth_globals.net_phone = net_phone;
[aadf01e]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);
[21580dd]304 return ERROR_CODE;
305 }
[aadf01e]306 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
307 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]308 return EOK;
309}
310
[aadf01e]311int eth_device_message(device_id_t device_id, services_t service, size_t mtu){
[21580dd]312 ERROR_DECLARE;
313
[aadf01e]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;
[21580dd]321
[aadf01e]322 fibril_rwlock_write_lock(&eth_globals.devices_lock);
[21580dd]323 // an existing device?
[aadf01e]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);
[21580dd]329 return EEXIST;
330 }else{
331 // update mtu
[aadf01e]332 if((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags))){
[21580dd]333 device->mtu = mtu;
334 }else{
[aadf01e]335 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
[21580dd]336 }
[aadf01e]337 printf("Device %d already exists:\tMTU\t= %d\n", device->device_id, device->mtu);
338 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]339 // notify all upper layer modules
[aadf01e]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);
[21580dd]345 }
346 }
[aadf01e]347 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]348 return EOK;
349 }
350 }else{
351 // create a new device
[aadf01e]352 device = (eth_device_ref) malloc(sizeof(eth_device_t));
353 if(! device){
354 return ENOMEM;
355 }
[21580dd]356 device->device_id = device_id;
357 device->service = service;
358 device->flags = 0;
[aadf01e]359 if((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags))){
[21580dd]360 device->mtu = mtu;
361 }else{
[aadf01e]362 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
[21580dd]363 }
[aadf01e]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);
[21580dd]368 return ERROR_CODE;
369 }
[aadf01e]370 if(configuration){
371 if(! str_lcmp(configuration[0].value, "DIX", configuration[0].length)){
[21580dd]372 device->flags |= ETH_DIX;
[aadf01e]373 }else if(! str_lcmp(configuration[0].value, "8023_2_LSAP", configuration[0].length)){
[21580dd]374 device->flags |= ETH_8023_2_LSAP;
375 }else device->flags |= ETH_8023_2_SNAP;
[aadf01e]376 if((configuration[1].value) && (configuration[1].value[0] == 'y')){
[21580dd]377 device->flags |= ETH_DUMMY;
378 }
[aadf01e]379 net_free_settings(configuration, data);
[21580dd]380 }else{
381 device->flags |= ETH_8023_2_SNAP;
382 }
383 // bind the device driver
[aadf01e]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);
[21580dd]388 return device->phone;
389 }
390 // get hardware address
[aadf01e]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);
[21580dd]394 return ERROR_CODE;
395 }
396 // add to the cache
[aadf01e]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);
[21580dd]403 return index;
404 }
[24ab58b3]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);
[21580dd]411 }
[aadf01e]412 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
[21580dd]413 return EOK;
414}
415
[aadf01e]416eth_proto_ref eth_process_packet(int flags, packet_t packet){
[21580dd]417 ERROR_DECLARE;
418
[aadf01e]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);
[21580dd]430 }
[aadf01e]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){
[21580dd]436 // DIX Ethernet
[aadf01e]437 prefix = sizeof(eth_header_t);
[21580dd]438 suffix = 0;
[aadf01e]439 fcs = (eth_fcs_ref) data + length - sizeof(eth_fcs_t);
440 length -= sizeof(eth_fcs_t);
441 }else if(type <= ETH_MAX_CONTENT){
[21580dd]442 // translate "LSAP" values
[aadf01e]443 if((header->lsap.dsap == ETH_LSAP_GLSAP) && (header->lsap.ssap == ETH_LSAP_GLSAP)){
[21580dd]444 // raw packet
445 // discard
446 return NULL;
[aadf01e]447 }else if((header->lsap.dsap == ETH_LSAP_SNAP) && (header->lsap.ssap == ETH_LSAP_SNAP)){
[21580dd]448 // IEEE 802.3 + 802.2 + LSAP + SNAP
449 // organization code not supported
[aadf01e]450 type = ntohs(header->snap.ethertype);
451 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t);
[21580dd]452 }else{
453 // IEEE 802.3 + 802.2 LSAP
[aadf01e]454 type = lsap_map(header->lsap.dsap);
455 prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t);
[21580dd]456 }
[aadf01e]457 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0u;
458 fcs = (eth_fcs_ref) data + prefix + type + suffix;
[21580dd]459 suffix += length - prefix - type;
460 length = prefix + type + suffix;
461 }else{
462 // invalid length/type, should not occurr
463 return NULL;
464 }
[aadf01e]465 if(IS_DUMMY(flags)){
466 if((~ compute_crc32(~ 0u, data, length * 8)) != ntohl(*fcs)){
[21580dd]467 return NULL;
468 }
[aadf01e]469 suffix += sizeof(eth_fcs_t);
[21580dd]470 }
[aadf01e]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))){
[21580dd]473 return NULL;
474 }
[aadf01e]475 return eth_protos_find(&eth_globals.protos, type);
[21580dd]476}
477
[14f1db0]478int nil_received_msg_local(int nil_phone, device_id_t device_id, packet_t packet, services_t target){
[aadf01e]479 eth_proto_ref proto;
480 packet_t next;
481 eth_device_ref device;
482 int flags;
[21580dd]483
[aadf01e]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);
[21580dd]488 return ENOENT;
489 }
490 flags = device->flags;
[aadf01e]491 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
492 fibril_rwlock_read_lock(&eth_globals.protos_lock);
[21580dd]493 do{
[aadf01e]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);
[21580dd]498 }else{
499 // drop invalid/unknown
[14f1db0]500 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
[21580dd]501 }
502 packet = next;
[aadf01e]503 }while(packet);
504 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
[21580dd]505 return EOK;
506}
507
[aadf01e]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;
[21580dd]510
[aadf01e]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);
[21580dd]518 return ENOENT;
519 }
[aadf01e]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;
[21580dd]525 return EOK;
526}
527
[aadf01e]528int eth_addr_message(device_id_t device_id, eth_addr_type_t type, measured_string_ref * address){
529 eth_device_ref device;
[21580dd]530
[aadf01e]531 if(! address){
532 return EBADMEM;
533 }
534 if(type == ETH_BROADCAST_ADDR){
535 *address = eth_globals.broadcast_addr;
[21580dd]536 }else{
[aadf01e]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);
[21580dd]541 return ENOENT;
542 }
[aadf01e]543 *address = device->addr;
544 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]545 }
[aadf01e]546 return (*address) ? EOK : ENOENT;
[21580dd]547}
548
[aadf01e]549int eth_register_message(services_t service, int phone){
550 eth_proto_ref proto;
551 int protocol;
552 int index;
[21580dd]553
[aadf01e]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){
[21580dd]561 proto->phone = phone;
[aadf01e]562 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]563 return EOK;
564 }else{
[aadf01e]565 proto = (eth_proto_ref) malloc(sizeof(eth_proto_t));
566 if(! proto){
567 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]568 return ENOMEM;
569 }
570 proto->service = service;
571 proto->protocol = protocol;
572 proto->phone = phone;
[aadf01e]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);
[21580dd]577 return index;
578 }
579 }
[24ab58b3]580
581 printf("%s: Protocol registered (protocol: %d, service: %d, phone: %d)\n",
582 NAME, proto->protocol, proto->service, proto->phone);
583
[aadf01e]584 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
[21580dd]585 return EOK;
586}
587
[aadf01e]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);
[21580dd]617 }
[aadf01e]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));
[21580dd]634 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
635 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
[aadf01e]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;
[21580dd]646 header->lsap.ssap = header->lsap.dsap;
647 header->lsap.ctrl = IEEE_8023_2_UI;
[aadf01e]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];
[21580dd]655 }
[aadf01e]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 }
[80ce111]664 preamble->sfd = ETH_SFD;
[aadf01e]665 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
666 if(! fcs){
667 return ENOMEM;
668 }
669 *fcs = htonl(~ compute_crc32(~ 0u, src, length * 8));
[21580dd]670 }
671 return EOK;
672}
673
[aadf01e]674int eth_send_message(device_id_t device_id, packet_t packet, services_t sender){
[21580dd]675 ERROR_DECLARE;
676
[aadf01e]677 eth_device_ref device;
678 packet_t next;
679 packet_t tmp;
680 int ethertype;
[21580dd]681
[aadf01e]682 ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
683 if(! ethertype){
[14f1db0]684 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
[21580dd]685 return EINVAL;
686 }
[aadf01e]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);
[21580dd]691 return ENOENT;
692 }
693 // process packet queue
694 next = packet;
695 do{
[aadf01e]696 if(ERROR_OCCURRED(eth_prepare_packet(device->flags, next, (uint8_t *) device->addr->value, ethertype, device->mtu))){
[21580dd]697 // release invalid packet
[aadf01e]698 tmp = pq_detach(next);
699 if(next == packet){
700 packet = tmp;
701 }
[14f1db0]702 pq_release_remote(eth_globals.net_phone, packet_get_id(next));
[21580dd]703 next = tmp;
704 }else{
[aadf01e]705 next = pq_next(next);
[21580dd]706 }
[aadf01e]707 }while(next);
[21580dd]708 // send packet queue
[aadf01e]709 if(packet){
710 netif_send_msg(device->phone, device_id, packet, SERVICE_ETHERNET);
[21580dd]711 }
[aadf01e]712 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
[21580dd]713 return EOK;
714}
715
[14f1db0]716int nil_message_standalone(const char *name, ipc_callid_t callid, ipc_call_t *call,
[24ab58b3]717 ipc_call_t *answer, int *answer_count)
718{
[21580dd]719 ERROR_DECLARE;
[24ab58b3]720
[aadf01e]721 measured_string_ref address;
722 packet_t packet;
[e417b96]723 size_t addrlen;
724 size_t prefix;
725 size_t suffix;
726 size_t content;
[24ab58b3]727
[aadf01e]728 *answer_count = 0;
[24ab58b3]729 switch (IPC_GET_METHOD(*call)) {
[21580dd]730 case IPC_M_PHONE_HUNGUP:
731 return EOK;
732 case NET_NIL_DEVICE:
[24ab58b3]733 return eth_device_message(IPC_GET_DEVICE(call),
734 IPC_GET_SERVICE(call), IPC_GET_MTU(call));
[21580dd]735 case NET_NIL_SEND:
[14f1db0]736 ERROR_PROPAGATE(packet_translate_remote(eth_globals.net_phone, &packet,
[24ab58b3]737 IPC_GET_PACKET(call)));
738 return eth_send_message(IPC_GET_DEVICE(call), packet,
739 IPC_GET_SERVICE(call));
[21580dd]740 case NET_NIL_PACKET_SPACE:
[24ab58b3]741 ERROR_PROPAGATE(eth_packet_space_message(IPC_GET_DEVICE(call),
742 &addrlen, &prefix, &content, &suffix));
[e417b96]743 IPC_SET_ADDR(answer, addrlen);
744 IPC_SET_PREFIX(answer, prefix);
745 IPC_SET_CONTENT(answer, content);
746 IPC_SET_SUFFIX(answer, suffix);
[aadf01e]747 *answer_count = 4;
[21580dd]748 return EOK;
749 case NET_NIL_ADDR:
[24ab58b3]750 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call),
751 ETH_LOCAL_ADDR, &address));
[aadf01e]752 return measured_strings_reply(address, 1);
[21580dd]753 case NET_NIL_BROADCAST_ADDR:
[24ab58b3]754 ERROR_PROPAGATE(eth_addr_message(IPC_GET_DEVICE(call),
755 ETH_BROADCAST_ADDR, &address));
[aadf01e]756 return measured_strings_reply(address, 1);
[21580dd]757 case IPC_M_CONNECT_TO_ME:
[24ab58b3]758 return eth_register_message(NIL_GET_PROTO(call),
759 IPC_GET_PHONE(call));
[21580dd]760 }
[24ab58b3]761
[21580dd]762 return ENOTSUP;
763}
764
[aadf01e]765void eth_receiver(ipc_callid_t iid, ipc_call_t * icall){
[21580dd]766 ERROR_DECLARE;
767
[aadf01e]768 packet_t packet;
[21580dd]769
[aadf01e]770 while(true){
771// printf("message %d - %d\n", IPC_GET_METHOD(*icall), NET_NIL_FIRST);
772 switch(IPC_GET_METHOD(*icall)){
[21580dd]773 case NET_NIL_DEVICE_STATE:
[14f1db0]774 nil_device_state_msg_local(0, IPC_GET_DEVICE(icall), IPC_GET_STATE(icall));
[aadf01e]775 ipc_answer_0(iid, EOK);
[21580dd]776 break;
777 case NET_NIL_RECEIVED:
[14f1db0]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);
[21580dd]780 }
[aadf01e]781 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
[21580dd]782 break;
783 default:
[aadf01e]784 ipc_answer_0(iid, (ipcarg_t) ENOTSUP);
[21580dd]785 }
[aadf01e]786 iid = async_get_call(icall);
[21580dd]787 }
788}
789
[14f1db0]790#ifndef CONFIG_NETIF_NIL_BUNDLE
[849ed54]791
792/** Default thread for new connections.
793 *
[14f1db0]794 * @param[in] iid The initial message identifier.
795 * @param[in] icall The initial message call structure.
[849ed54]796 *
797 */
[14f1db0]798static void nil_client_connection(ipc_callid_t iid, ipc_call_t *icall)
[849ed54]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 */
[14f1db0]818 int res = nil_module_message_standalone(NAME, callid, &call, &answer,
[24ab58b3]819 &answer_count);
[849ed54]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 */
[14f1db0]835 if (ERROR_OCCURRED(nil_module_start_standalone(nil_client_connection)))
[849ed54]836 return ERROR_CODE;
837
838 return EOK;
839}
840
[14f1db0]841#endif /* CONFIG_NETIF_NIL_BUNDLE */
[849ed54]842
[21580dd]843/** @}
844 */
Note: See TracBrowser for help on using the repository browser.