eth.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <async.h>
00039 #include <malloc.h>
00040 #include <mem.h>
00041 #include <stdio.h>
00042 #include <byteorder.h>
00043 #include <str.h>
00044 #include <errno.h>
00045 #include <ipc/nil.h>
00046 #include <ipc/net.h>
00047 #include <ipc/services.h>
00048 #include <net/modules.h>
00049 #include <net_checksum.h>
00050 #include <ethernet_lsap.h>
00051 #include <ethernet_protocols.h>
00052 #include <protocol_map.h>
00053 #include <net/device.h>
00054 #include <netif_remote.h>
00055 #include <net_interface.h>
00056 #include <il_remote.h>
00057 #include <adt/measured_strings.h>
00058 #include <packet_client.h>
00059 #include <packet_remote.h>
00060 #include <nil_skel.h>
00061 
00062 #include "eth.h"
00063 
00065 #define NAME  "eth"
00066 
00068 #define ETH_PREFIX \
00069         (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + \
00070             sizeof(eth_header_snap_t))
00071 
00073 #define ETH_SUFFIX  (sizeof(eth_fcs_t))
00074 
00076 #define ETH_MAX_CONTENT  1500u
00077 
00079 #define ETH_MIN_CONTENT  46u
00080 
00082 #define ETH_MAX_TAGGED_CONTENT(flags) \
00083         (ETH_MAX_CONTENT - \
00084             ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
00085             sizeof(eth_header_lsap_t) : 0) - \
00086             (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
00087 
00089 #define ETH_MIN_TAGGED_CONTENT(flags) \
00090         (ETH_MIN_CONTENT - \
00091             ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
00092             sizeof(eth_header_lsap_t) : 0) - \
00093             (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
00094 
00096 #define ETH_DUMMY_SHIFT  0
00097 
00099 #define ETH_MODE_SHIFT  1
00100 
00104 #define ETH_DUMMY  (1 << ETH_DUMMY_SHIFT)
00105 
00109 #define IS_DUMMY(flags)  ((flags) & ETH_DUMMY)
00110 
00116 #define ETH_MODE_MASK  (3 << ETH_MODE_SHIFT)
00117 
00119 #define ETH_DIX  (1 << ETH_MODE_SHIFT)
00120 
00127 #define IS_DIX(flags)  (((flags) & ETH_MODE_MASK) == ETH_DIX)
00128 
00130 #define ETH_8023_2_LSAP  (2 << ETH_MODE_SHIFT)
00131 
00138 #define IS_8023_2_LSAP(flags)  (((flags) & ETH_MODE_MASK) == ETH_8023_2_LSAP)
00139 
00141 #define ETH_8023_2_SNAP  (3 << ETH_MODE_SHIFT)
00142 
00149 #define IS_8023_2_SNAP(flags)  (((flags) & ETH_MODE_MASK) == ETH_8023_2_SNAP)
00150 
00154 typedef enum eth_addr_type eth_addr_type_t;
00155 
00157 enum eth_addr_type {
00159         ETH_LOCAL_ADDR,
00161         ETH_BROADCAST_ADDR
00162 };
00163 
00165 eth_globals_t eth_globals;
00166 
00167 DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t);
00168 INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
00169 
00170 int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
00171 {
00172         int index;
00173         eth_proto_t *proto;
00174 
00175         fibril_rwlock_read_lock(&eth_globals.protos_lock);
00176         for (index = eth_protos_count(&eth_globals.protos) - 1; index >= 0;
00177             index--) {
00178                 proto = eth_protos_get_index(&eth_globals.protos, index);
00179                 if (proto && proto->phone) {
00180                         il_device_state_msg(proto->phone, device_id, state,
00181                             proto->service);
00182                 }
00183         }
00184         fibril_rwlock_read_unlock(&eth_globals.protos_lock);
00185         
00186         return EOK;
00187 }
00188 
00189 int nil_initialize(int net_phone)
00190 {
00191         int rc;
00192 
00193         fibril_rwlock_initialize(&eth_globals.devices_lock);
00194         fibril_rwlock_initialize(&eth_globals.protos_lock);
00195         
00196         fibril_rwlock_write_lock(&eth_globals.devices_lock);
00197         fibril_rwlock_write_lock(&eth_globals.protos_lock);
00198         eth_globals.net_phone = net_phone;
00199 
00200         eth_globals.broadcast_addr =
00201             measured_string_create_bulk((uint8_t *) "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ADDR);
00202         if (!eth_globals.broadcast_addr) {
00203                 rc = ENOMEM;
00204                 goto out;
00205         }
00206 
00207         rc = eth_devices_initialize(&eth_globals.devices);
00208         if (rc != EOK) {
00209                 free(eth_globals.broadcast_addr);
00210                 goto out;
00211         }
00212 
00213         rc = eth_protos_initialize(&eth_globals.protos);
00214         if (rc != EOK) {
00215                 free(eth_globals.broadcast_addr);
00216                 eth_devices_destroy(&eth_globals.devices, free);
00217         }
00218 out:
00219         fibril_rwlock_write_unlock(&eth_globals.protos_lock);
00220         fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00221         
00222         return rc;
00223 }
00224 
00231 static void eth_receiver(ipc_callid_t iid, ipc_call_t *icall)
00232 {
00233         packet_t *packet;
00234         int rc;
00235 
00236         while (true) {
00237                 switch (IPC_GET_IMETHOD(*icall)) {
00238                 case NET_NIL_DEVICE_STATE:
00239                         nil_device_state_msg_local(0, IPC_GET_DEVICE(*icall),
00240                             IPC_GET_STATE(*icall));
00241                         async_answer_0(iid, EOK);
00242                         break;
00243                 case NET_NIL_RECEIVED:
00244                         rc = packet_translate_remote(eth_globals.net_phone,
00245                             &packet, IPC_GET_PACKET(*icall));
00246                         if (rc == EOK)
00247                                 rc = nil_received_msg_local(0,
00248                                     IPC_GET_DEVICE(*icall), packet, 0);
00249                         
00250                         async_answer_0(iid, (sysarg_t) rc);
00251                         break;
00252                 default:
00253                         async_answer_0(iid, (sysarg_t) ENOTSUP);
00254                 }
00255                 
00256                 iid = async_get_call(icall);
00257         }
00258 }
00259 
00277 static int eth_device_message(device_id_t device_id, services_t service,
00278     size_t mtu)
00279 {
00280         eth_device_t *device;
00281         int index;
00282         measured_string_t names[2] = {
00283                 {
00284                         (uint8_t *) "ETH_MODE",
00285                         8
00286                 },
00287                 {
00288                         (uint8_t *) "ETH_DUMMY",
00289                         9
00290                 }
00291         };
00292         measured_string_t *configuration;
00293         size_t count = sizeof(names) / sizeof(measured_string_t);
00294         uint8_t *data;
00295         eth_proto_t *proto;
00296         int rc;
00297 
00298         fibril_rwlock_write_lock(&eth_globals.devices_lock);
00299         /* An existing device? */
00300         device = eth_devices_find(&eth_globals.devices, device_id);
00301         if (device) {
00302                 if (device->service != service) {
00303                         printf("Device %d already exists\n", device->device_id);
00304                         fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00305                         return EEXIST;
00306                 }
00307                 
00308                 /* Update mtu */
00309                 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
00310                         device->mtu = mtu;
00311                 else
00312                         device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
00313                 
00314                 printf("Device %d already exists:\tMTU\t= %zu\n",
00315                     device->device_id, device->mtu);
00316                 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00317                 
00318                 /* Notify all upper layer modules */
00319                 fibril_rwlock_read_lock(&eth_globals.protos_lock);
00320                 for (index = 0; index < eth_protos_count(&eth_globals.protos);
00321                     index++) {
00322                         proto = eth_protos_get_index(&eth_globals.protos,
00323                             index);
00324                         if (proto->phone) {
00325                                 il_mtu_changed_msg(proto->phone,
00326                                     device->device_id, device->mtu,
00327                                     proto->service);
00328                         }
00329                 }
00330 
00331                 fibril_rwlock_read_unlock(&eth_globals.protos_lock);
00332                 return EOK;
00333         }
00334         
00335         /* Create a new device */
00336         device = (eth_device_t *) malloc(sizeof(eth_device_t));
00337         if (!device)
00338                 return ENOMEM;
00339 
00340         device->device_id = device_id;
00341         device->service = service;
00342         device->flags = 0;
00343         if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
00344                 device->mtu = mtu;
00345         else
00346                 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
00347 
00348         configuration = &names[0];
00349         rc = net_get_device_conf_req(eth_globals.net_phone, device->device_id,
00350             &configuration, count, &data);
00351         if (rc != EOK) {
00352                 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00353                 free(device);
00354                 return rc;
00355         }
00356 
00357         if (configuration) {
00358                 if (!str_lcmp((char *) configuration[0].value, "DIX",
00359                     configuration[0].length)) {
00360                         device->flags |= ETH_DIX;
00361                 } else if(!str_lcmp((char *) configuration[0].value, "8023_2_LSAP",
00362                     configuration[0].length)) {
00363                         device->flags |= ETH_8023_2_LSAP;
00364                 } else {
00365                         device->flags |= ETH_8023_2_SNAP;
00366                 }
00367                 
00368                 if (configuration[1].value &&
00369                     (configuration[1].value[0] == 'y')) {
00370                         device->flags |= ETH_DUMMY;
00371                 }
00372                 net_free_settings(configuration, data);
00373         } else {
00374                 device->flags |= ETH_8023_2_SNAP;
00375         }
00376         
00377         /* Bind the device driver */
00378         device->phone = netif_bind_service(device->service, device->device_id,
00379             SERVICE_ETHERNET, eth_receiver);
00380         if (device->phone < 0) {
00381                 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00382                 free(device);
00383                 return device->phone;
00384         }
00385         
00386         /* Get hardware address */
00387         rc = netif_get_addr_req(device->phone, device->device_id, &device->addr,
00388             &device->addr_data);
00389         if (rc != EOK) {
00390                 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00391                 free(device);
00392                 return rc;
00393         }
00394         
00395         /* Add to the cache */
00396         index = eth_devices_add(&eth_globals.devices, device->device_id,
00397             device);
00398         if (index < 0) {
00399                 fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00400                 free(device->addr);
00401                 free(device->addr_data);
00402                 free(device);
00403                 return index;
00404         }
00405         
00406         printf("%s: Device registered (id: %d, service: %d: mtu: %zu, "
00407             "mac: %02x:%02x:%02x:%02x:%02x:%02x, flags: 0x%x)\n",
00408             NAME, device->device_id, device->service, device->mtu,
00409             device->addr_data[0], device->addr_data[1],
00410             device->addr_data[2], device->addr_data[3],
00411             device->addr_data[4], device->addr_data[5], device->flags);
00412 
00413         fibril_rwlock_write_unlock(&eth_globals.devices_lock);
00414         return EOK;
00415 }
00416 
00428 static eth_proto_t *eth_process_packet(int flags, packet_t *packet)
00429 {
00430         eth_header_snap_t *header;
00431         size_t length;
00432         eth_type_t type;
00433         size_t prefix;
00434         size_t suffix;
00435         eth_fcs_t *fcs;
00436         uint8_t *data;
00437         int rc;
00438 
00439         length = packet_get_data_length(packet);
00440         
00441         if (IS_DUMMY(flags))
00442                 packet_trim(packet, sizeof(eth_preamble_t), 0);
00443         if (length < sizeof(eth_header_t) + ETH_MIN_CONTENT +
00444             (IS_DUMMY(flags) ? ETH_SUFFIX : 0))
00445                 return NULL;
00446         
00447         data = packet_get_data(packet);
00448         header = (eth_header_snap_t *) data;
00449         type = ntohs(header->header.ethertype);
00450         
00451         if (type >= ETH_MIN_PROTO) {
00452                 /* DIX Ethernet */
00453                 prefix = sizeof(eth_header_t);
00454                 suffix = 0;
00455                 fcs = (eth_fcs_t *) data + length - sizeof(eth_fcs_t);
00456                 length -= sizeof(eth_fcs_t);
00457         } else if(type <= ETH_MAX_CONTENT) {
00458                 /* Translate "LSAP" values */
00459                 if ((header->lsap.dsap == ETH_LSAP_GLSAP) &&
00460                     (header->lsap.ssap == ETH_LSAP_GLSAP)) {
00461                         /* Raw packet -- discard */
00462                         return NULL;
00463                 } else if((header->lsap.dsap == ETH_LSAP_SNAP) &&
00464                     (header->lsap.ssap == ETH_LSAP_SNAP)) {
00465                         /*
00466                          * IEEE 802.3 + 802.2 + LSAP + SNAP
00467                          * organization code not supported
00468                          */
00469                         type = ntohs(header->snap.ethertype);
00470                         prefix = sizeof(eth_header_t) +
00471                             sizeof(eth_header_lsap_t) +
00472                             sizeof(eth_header_snap_t);
00473                 } else {
00474                         /* IEEE 802.3 + 802.2 LSAP */
00475                         type = lsap_map(header->lsap.dsap);
00476                         prefix = sizeof(eth_header_t) +
00477                             sizeof(eth_header_lsap_t);
00478                 }
00479 
00480                 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0U;
00481                 fcs = (eth_fcs_t *) data + prefix + type + suffix;
00482                 suffix += length - prefix - type;
00483                 length = prefix + type + suffix;
00484         } else {
00485                 /* Invalid length/type, should not occur */
00486                 return NULL;
00487         }
00488         
00489         if (IS_DUMMY(flags)) {
00490                 if (~compute_crc32(~0U, data, length * 8) != ntohl(*fcs))
00491                         return NULL;
00492                 suffix += sizeof(eth_fcs_t);
00493         }
00494         
00495         rc = packet_set_addr(packet, header->header.source_address,
00496             header->header.destination_address, ETH_ADDR);
00497         if (rc != EOK)
00498                 return NULL;
00499 
00500         rc = packet_trim(packet, prefix, suffix);
00501         if (rc != EOK)
00502                 return NULL;
00503         
00504         return eth_protos_find(&eth_globals.protos, type);
00505 }
00506 
00507 int nil_received_msg_local(int nil_phone, device_id_t device_id,
00508     packet_t *packet, services_t target)
00509 {
00510         eth_proto_t *proto;
00511         packet_t *next;
00512         eth_device_t *device;
00513         int flags;
00514 
00515         fibril_rwlock_read_lock(&eth_globals.devices_lock);
00516         device = eth_devices_find(&eth_globals.devices, device_id);
00517         if (!device) {
00518                 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00519                 return ENOENT;
00520         }
00521 
00522         flags = device->flags;
00523         fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00524         
00525         fibril_rwlock_read_lock(&eth_globals.protos_lock);
00526         do {
00527                 next = pq_detach(packet);
00528                 proto = eth_process_packet(flags, packet);
00529                 if (proto) {
00530                         il_received_msg(proto->phone, device_id, packet,
00531                             proto->service);
00532                 } else {
00533                         /* Drop invalid/unknown */
00534                         pq_release_remote(eth_globals.net_phone,
00535                             packet_get_id(packet));
00536                 }
00537                 packet = next;
00538         } while(packet);
00539 
00540         fibril_rwlock_read_unlock(&eth_globals.protos_lock);
00541         return EOK;
00542 }
00543 
00555 static int eth_packet_space_message(device_id_t device_id, size_t *addr_len,
00556     size_t *prefix, size_t *content, size_t *suffix)
00557 {
00558         eth_device_t *device;
00559 
00560         if (!addr_len || !prefix || !content || !suffix)
00561                 return EBADMEM;
00562         
00563         fibril_rwlock_read_lock(&eth_globals.devices_lock);
00564         device = eth_devices_find(&eth_globals.devices, device_id);
00565         if (!device) {
00566                 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00567                 return ENOENT;
00568         }
00569 
00570         *content = device->mtu;
00571         fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00572         
00573         *addr_len = ETH_ADDR;
00574         *prefix = ETH_PREFIX;
00575         *suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
00576 
00577         return EOK;
00578 }
00579 
00589 static int eth_addr_message(device_id_t device_id, eth_addr_type_t type,
00590     measured_string_t **address)
00591 {
00592         eth_device_t *device;
00593 
00594         if (!address)
00595                 return EBADMEM;
00596 
00597         if (type == ETH_BROADCAST_ADDR) {
00598                 *address = eth_globals.broadcast_addr;
00599         } else {
00600                 fibril_rwlock_read_lock(&eth_globals.devices_lock);
00601                 device = eth_devices_find(&eth_globals.devices, device_id);
00602                 if (!device) {
00603                         fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00604                         return ENOENT;
00605                 }
00606                 *address = device->addr;
00607                 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00608         }
00609         
00610         return (*address) ? EOK : ENOENT;
00611 }
00612 
00623 static int eth_register_message(services_t service, int phone)
00624 {
00625         eth_proto_t *proto;
00626         int protocol;
00627         int index;
00628 
00629         protocol = protocol_map(SERVICE_ETHERNET, service);
00630         if (!protocol)
00631                 return ENOENT;
00632 
00633         fibril_rwlock_write_lock(&eth_globals.protos_lock);
00634         proto = eth_protos_find(&eth_globals.protos, protocol);
00635         if (proto) {
00636                 proto->phone = phone;
00637                 fibril_rwlock_write_unlock(&eth_globals.protos_lock);
00638                 return EOK;
00639         } else {
00640                 proto = (eth_proto_t *) malloc(sizeof(eth_proto_t));
00641                 if (!proto) {
00642                         fibril_rwlock_write_unlock(&eth_globals.protos_lock);
00643                         return ENOMEM;
00644                 }
00645 
00646                 proto->service = service;
00647                 proto->protocol = protocol;
00648                 proto->phone = phone;
00649 
00650                 index = eth_protos_add(&eth_globals.protos, protocol, proto);
00651                 if (index < 0) {
00652                         fibril_rwlock_write_unlock(&eth_globals.protos_lock);
00653                         free(proto);
00654                         return index;
00655                 }
00656         }
00657         
00658         printf("%s: Protocol registered (protocol: %d, service: %d, phone: "
00659             "%d)\n", NAME, proto->protocol, proto->service, proto->phone);
00660         
00661         fibril_rwlock_write_unlock(&eth_globals.protos_lock);
00662         return EOK;
00663 }
00664 
00678 static int
00679 eth_prepare_packet(int flags, packet_t *packet, uint8_t *src_addr, int ethertype,
00680     size_t mtu)
00681 {
00682         eth_header_snap_t *header;
00683         eth_header_lsap_t *header_lsap;
00684         eth_header_t *header_dix;
00685         eth_fcs_t *fcs;
00686         uint8_t *src;
00687         uint8_t *dest;
00688         size_t length;
00689         int i;
00690         void *padding;
00691         eth_preamble_t *preamble;
00692 
00693         i = packet_get_addr(packet, &src, &dest);
00694         if (i < 0)
00695                 return i;
00696         if (i != ETH_ADDR)
00697                 return EINVAL;
00698 
00699         length = packet_get_data_length(packet);
00700         if (length > mtu)
00701                 return EINVAL;
00702         
00703         if (length < ETH_MIN_TAGGED_CONTENT(flags)) {
00704                 padding = packet_suffix(packet,
00705                     ETH_MIN_TAGGED_CONTENT(flags) - length);
00706                 if (!padding)
00707                         return ENOMEM;
00708 
00709                 bzero(padding, ETH_MIN_TAGGED_CONTENT(flags) - length);
00710         }
00711         
00712         if (IS_DIX(flags)) {
00713                 header_dix = PACKET_PREFIX(packet, eth_header_t);
00714                 if (!header_dix)
00715                         return ENOMEM;
00716                 
00717                 header_dix->ethertype = (uint16_t) ethertype;
00718                 memcpy(header_dix->source_address, src_addr, ETH_ADDR);
00719                 memcpy(header_dix->destination_address, dest, ETH_ADDR);
00720                 src = &header_dix->destination_address[0];
00721         } else if(IS_8023_2_LSAP(flags)) {
00722                 header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
00723                 if (!header_lsap)
00724                         return ENOMEM;
00725                 
00726                 header_lsap->header.ethertype = htons(length +
00727                     sizeof(eth_header_lsap_t));
00728                 header_lsap->lsap.dsap = lsap_unmap(ntohs(ethertype));
00729                 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
00730                 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
00731                 memcpy(header_lsap->header.source_address, src_addr, ETH_ADDR);
00732                 memcpy(header_lsap->header.destination_address, dest, ETH_ADDR);
00733                 src = &header_lsap->header.destination_address[0];
00734         } else if(IS_8023_2_SNAP(flags)) {
00735                 header = PACKET_PREFIX(packet, eth_header_snap_t);
00736                 if (!header)
00737                         return ENOMEM;
00738                 
00739                 header->header.ethertype = htons(length +
00740                     sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t));
00741                 header->lsap.dsap = (uint16_t) ETH_LSAP_SNAP;
00742                 header->lsap.ssap = header->lsap.dsap;
00743                 header->lsap.ctrl = IEEE_8023_2_UI;
00744                 
00745                 for (i = 0; i < 3; ++ i)
00746                         header->snap.protocol[i] = 0;
00747                 
00748                 header->snap.ethertype = (uint16_t) ethertype;
00749                 memcpy(header->header.source_address, src_addr, ETH_ADDR);
00750                 memcpy(header->header.destination_address, dest, ETH_ADDR);
00751                 src = &header->header.destination_address[0];
00752         }
00753         
00754         if (IS_DUMMY(flags)) {
00755                 preamble = PACKET_PREFIX(packet, eth_preamble_t);
00756                 if (!preamble)
00757                         return ENOMEM;
00758                 
00759                 for (i = 0; i < 7; ++ i)
00760                         preamble->preamble[i] = ETH_PREAMBLE;
00761                 
00762                 preamble->sfd = ETH_SFD;
00763                 
00764                 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
00765                 if (!fcs)
00766                         return ENOMEM;
00767 
00768                 *fcs = htonl(~compute_crc32(~0U, src, length * 8));
00769         }
00770         
00771         return EOK;
00772 }
00773 
00786 static int eth_send_message(device_id_t device_id, packet_t *packet,
00787     services_t sender)
00788 {
00789         eth_device_t *device;
00790         packet_t *next;
00791         packet_t *tmp;
00792         int ethertype;
00793         int rc;
00794 
00795         ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
00796         if (!ethertype) {
00797                 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
00798                 return EINVAL;
00799         }
00800         
00801         fibril_rwlock_read_lock(&eth_globals.devices_lock);
00802         device = eth_devices_find(&eth_globals.devices, device_id);
00803         if (!device) {
00804                 fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00805                 return ENOENT;
00806         }
00807         
00808         /* Process packet queue */
00809         next = packet;
00810         do {
00811                 rc = eth_prepare_packet(device->flags, next,
00812                     (uint8_t *) device->addr->value, ethertype, device->mtu);
00813                 if (rc != EOK) {
00814                         /* Release invalid packet */
00815                         tmp = pq_detach(next);
00816                         if (next == packet)
00817                                 packet = tmp;
00818                         pq_release_remote(eth_globals.net_phone,
00819                             packet_get_id(next));
00820                         next = tmp;
00821                 } else {
00822                         next = pq_next(next);
00823                 }
00824         } while(next);
00825         
00826         /* Send packet queue */
00827         if (packet) {
00828                 netif_send_msg(device->phone, device_id, packet,
00829                     SERVICE_ETHERNET);
00830         }
00831 
00832         fibril_rwlock_read_unlock(&eth_globals.devices_lock);
00833         return EOK;
00834 }
00835 
00836 int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
00837     ipc_call_t *answer, size_t *answer_count)
00838 {
00839         measured_string_t *address;
00840         packet_t *packet;
00841         size_t addrlen;
00842         size_t prefix;
00843         size_t suffix;
00844         size_t content;
00845         int rc;
00846         
00847         *answer_count = 0;
00848         switch (IPC_GET_IMETHOD(*call)) {
00849         case IPC_M_PHONE_HUNGUP:
00850                 return EOK;
00851         
00852         case NET_NIL_DEVICE:
00853                 return eth_device_message(IPC_GET_DEVICE(*call),
00854                     IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
00855         case NET_NIL_SEND:
00856                 rc = packet_translate_remote(eth_globals.net_phone, &packet,
00857                     IPC_GET_PACKET(*call));
00858                 if (rc != EOK)
00859                         return rc;
00860                 return eth_send_message(IPC_GET_DEVICE(*call), packet,
00861                     IPC_GET_SERVICE(*call));
00862         case NET_NIL_PACKET_SPACE:
00863                 rc = eth_packet_space_message(IPC_GET_DEVICE(*call), &addrlen,
00864                     &prefix, &content, &suffix);
00865                 if (rc != EOK)
00866                         return rc;
00867                 IPC_SET_ADDR(*answer, addrlen);
00868                 IPC_SET_PREFIX(*answer, prefix);
00869                 IPC_SET_CONTENT(*answer, content);
00870                 IPC_SET_SUFFIX(*answer, suffix);
00871                 *answer_count = 4;
00872                 return EOK;
00873         case NET_NIL_ADDR:
00874                 rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_LOCAL_ADDR,
00875                     &address);
00876                 if (rc != EOK)
00877                         return rc;
00878                 return measured_strings_reply(address, 1);
00879         case NET_NIL_BROADCAST_ADDR:
00880                 rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_BROADCAST_ADDR,
00881                     &address);
00882                 if (rc != EOK)
00883                         return EOK;
00884                 return measured_strings_reply(address, 1);
00885         case IPC_M_CONNECT_TO_ME:
00886                 return eth_register_message(NIL_GET_PROTO(*call),
00887                     IPC_GET_PHONE(*call));
00888         }
00889         
00890         return ENOTSUP;
00891 }
00892 
00893 int main(int argc, char *argv[])
00894 {
00895         /* Start the module */
00896         return nil_module_start(SERVICE_ETHERNET);
00897 }
00898 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7