| 1 | /*
 | 
|---|
| 2 |  * Copyright (c) 2009 Lukas Mejdrech
 | 
|---|
| 3 |  * All rights reserved.
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  * Redistribution and use in source and binary forms, with or without
 | 
|---|
| 6 |  * modification, are permitted provided that the following conditions
 | 
|---|
| 7 |  * are met:
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * - Redistributions of source code must retain the above copyright
 | 
|---|
| 10 |  *   notice, this list of conditions and the following disclaimer.
 | 
|---|
| 11 |  * - Redistributions in binary form must reproduce the above copyright
 | 
|---|
| 12 |  *   notice, this list of conditions and the following disclaimer in the
 | 
|---|
| 13 |  *   documentation and/or other materials provided with the distribution.
 | 
|---|
| 14 |  * - The name of the author may not be used to endorse or promote products
 | 
|---|
| 15 |  *   derived from this software without specific prior written permission.
 | 
|---|
| 16 |  *
 | 
|---|
| 17 |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
|---|
| 18 |  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
|---|
| 19 |  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
|---|
| 20 |  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
|---|
| 21 |  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
|---|
| 22 |  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
|---|
| 23 |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
|---|
| 24 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
|---|
| 25 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
|---|
| 26 |  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
|---|
| 27 |  */
 | 
|---|
| 28 | 
 | 
|---|
| 29 | /** @addtogroup eth
 | 
|---|
| 30 |  *  @{
 | 
|---|
| 31 |  */
 | 
|---|
| 32 | 
 | 
|---|
| 33 | /** @file
 | 
|---|
| 34 |  *  Ethernet module implementation.
 | 
|---|
| 35 |  *  @see eth.h
 | 
|---|
| 36 |  */
 | 
|---|
| 37 | 
 | 
|---|
| 38 | #include <async.h>
 | 
|---|
| 39 | #include <malloc.h>
 | 
|---|
| 40 | #include <mem.h>
 | 
|---|
| 41 | #include <stdio.h>
 | 
|---|
| 42 | #include <byteorder.h>
 | 
|---|
| 43 | #include <str.h>
 | 
|---|
| 44 | #include <errno.h>
 | 
|---|
| 45 | 
 | 
|---|
| 46 | #include <ipc/ipc.h>
 | 
|---|
| 47 | #include <ipc/net.h>
 | 
|---|
| 48 | #include <ipc/services.h>
 | 
|---|
| 49 | 
 | 
|---|
| 50 | #include <net/modules.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_client.h>
 | 
|---|
| 62 | #include <packet_remote.h>
 | 
|---|
| 63 | #include <nil_local.h>
 | 
|---|
| 64 | 
 | 
|---|
| 65 | #include "eth.h"
 | 
|---|
| 66 | #include "eth_header.h"
 | 
|---|
| 67 | 
 | 
|---|
| 68 | /** The module name. */
 | 
|---|
| 69 | #define NAME  "eth"
 | 
|---|
| 70 | 
 | 
|---|
| 71 | /** Reserved packet prefix length. */
 | 
|---|
| 72 | #define ETH_PREFIX \
 | 
|---|
| 73 |         (sizeof(eth_header_t) + sizeof(eth_header_lsap_t) + \
 | 
|---|
| 74 |         sizeof(eth_header_snap_t))
 | 
|---|
| 75 | 
 | 
|---|
| 76 | /** Reserved packet suffix length. */
 | 
|---|
| 77 | #define ETH_SUFFIX \
 | 
|---|
| 78 |         sizeof(eth_fcs_t)
 | 
|---|
| 79 | 
 | 
|---|
| 80 | /** Maximum packet content length. */
 | 
|---|
| 81 | #define ETH_MAX_CONTENT 1500u
 | 
|---|
| 82 | 
 | 
|---|
| 83 | /** Minimum packet content length. */
 | 
|---|
| 84 | #define ETH_MIN_CONTENT 46u
 | 
|---|
| 85 | 
 | 
|---|
| 86 | /** Maximum tagged packet content length. */
 | 
|---|
| 87 | #define ETH_MAX_TAGGED_CONTENT(flags) \
 | 
|---|
| 88 |         (ETH_MAX_CONTENT - \
 | 
|---|
| 89 |         ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
 | 
|---|
| 90 |         sizeof(eth_header_lsap_t) : 0) - \
 | 
|---|
| 91 |         (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
 | 
|---|
| 92 | 
 | 
|---|
| 93 | /** Minimum tagged packet content length. */
 | 
|---|
| 94 | #define ETH_MIN_TAGGED_CONTENT(flags) \
 | 
|---|
| 95 |         (ETH_MIN_CONTENT - \
 | 
|---|
| 96 |         ((IS_8023_2_LSAP(flags) || IS_8023_2_SNAP(flags)) ? \
 | 
|---|
| 97 |         sizeof(eth_header_lsap_t) : 0) - \
 | 
|---|
| 98 |         (IS_8023_2_SNAP(flags) ? sizeof(eth_header_snap_t) : 0))
 | 
|---|
| 99 | 
 | 
|---|
| 100 | /** Dummy flag shift value. */
 | 
|---|
| 101 | #define ETH_DUMMY_SHIFT 0
 | 
|---|
| 102 | 
 | 
|---|
| 103 | /** Mode flag shift value. */
 | 
|---|
| 104 | #define ETH_MODE_SHIFT  1
 | 
|---|
| 105 | 
 | 
|---|
| 106 | /** Dummy device flag.
 | 
|---|
| 107 |  * Preamble and FCS are mandatory part of the packets.
 | 
|---|
| 108 |  */
 | 
|---|
| 109 | #define ETH_DUMMY               (1 << ETH_DUMMY_SHIFT)
 | 
|---|
| 110 | 
 | 
|---|
| 111 | /** Returns the dummy flag.
 | 
|---|
| 112 |  * @see ETH_DUMMY
 | 
|---|
| 113 |  */
 | 
|---|
| 114 | #define IS_DUMMY(flags)         ((flags) & ETH_DUMMY)
 | 
|---|
| 115 | 
 | 
|---|
| 116 | /** Device mode flags.
 | 
|---|
| 117 |  * @see ETH_DIX
 | 
|---|
| 118 |  * @see ETH_8023_2_LSAP
 | 
|---|
| 119 |  * @see ETH_8023_2_SNAP
 | 
|---|
| 120 |  */
 | 
|---|
| 121 | #define ETH_MODE_MASK           (3 << ETH_MODE_SHIFT)
 | 
|---|
| 122 | 
 | 
|---|
| 123 | /** DIX Ethernet mode flag. */
 | 
|---|
| 124 | #define ETH_DIX                 (1 << ETH_MODE_SHIFT)
 | 
|---|
| 125 | 
 | 
|---|
| 126 | /** Returns whether the DIX Ethernet mode flag is set.
 | 
|---|
| 127 |  *
 | 
|---|
| 128 |  * @param[in] flags     The ethernet flags.
 | 
|---|
| 129 |  * @see ETH_DIX
 | 
|---|
| 130 |  */
 | 
|---|
| 131 | #define IS_DIX(flags)           (((flags) & ETH_MODE_MASK) == ETH_DIX)
 | 
|---|
| 132 | 
 | 
|---|
| 133 | /** 802.3 + 802.2 + LSAP mode flag. */
 | 
|---|
| 134 | #define ETH_8023_2_LSAP         (2 << ETH_MODE_SHIFT)
 | 
|---|
| 135 | 
 | 
|---|
| 136 | /** Returns whether the 802.3 + 802.2 + LSAP mode flag is set.
 | 
|---|
| 137 |  *
 | 
|---|
| 138 |  * @param[in] flags     The ethernet flags.
 | 
|---|
| 139 |  * @see ETH_8023_2_LSAP
 | 
|---|
| 140 |  */
 | 
|---|
| 141 | #define IS_8023_2_LSAP(flags)   (((flags) & ETH_MODE_MASK) == ETH_8023_2_LSAP)
 | 
|---|
| 142 | 
 | 
|---|
| 143 | /** 802.3 + 802.2 + LSAP + SNAP mode flag. */
 | 
|---|
| 144 | #define ETH_8023_2_SNAP         (3 << ETH_MODE_SHIFT)
 | 
|---|
| 145 | 
 | 
|---|
| 146 | /** Returns whether the 802.3 + 802.2 + LSAP + SNAP mode flag is set.
 | 
|---|
| 147 |  *
 | 
|---|
| 148 |  * @param[in] flags     The ethernet flags.
 | 
|---|
| 149 |  * @see ETH_8023_2_SNAP
 | 
|---|
| 150 |  */
 | 
|---|
| 151 | #define IS_8023_2_SNAP(flags)   (((flags) & ETH_MODE_MASK) == ETH_8023_2_SNAP)
 | 
|---|
| 152 | 
 | 
|---|
| 153 | /** Type definition of the ethernet address type.
 | 
|---|
| 154 |  * @see eth_addr_type
 | 
|---|
| 155 |  */
 | 
|---|
| 156 | typedef enum eth_addr_type eth_addr_type_t;
 | 
|---|
| 157 | 
 | 
|---|
| 158 | /** Ethernet address type. */
 | 
|---|
| 159 | enum eth_addr_type {
 | 
|---|
| 160 |         /** Local address. */
 | 
|---|
| 161 |         ETH_LOCAL_ADDR,
 | 
|---|
| 162 |         /** Broadcast address. */
 | 
|---|
| 163 |         ETH_BROADCAST_ADDR
 | 
|---|
| 164 | };
 | 
|---|
| 165 | 
 | 
|---|
| 166 | /** Ethernet module global data. */
 | 
|---|
| 167 | eth_globals_t eth_globals;
 | 
|---|
| 168 | 
 | 
|---|
| 169 | DEVICE_MAP_IMPLEMENT(eth_devices, eth_device_t);
 | 
|---|
| 170 | INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
 | 
|---|
| 171 | 
 | 
|---|
| 172 | int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
 | 
|---|
| 173 | {
 | 
|---|
| 174 |         int index;
 | 
|---|
| 175 |         eth_proto_t *proto;
 | 
|---|
| 176 | 
 | 
|---|
| 177 |         fibril_rwlock_read_lock(ð_globals.protos_lock);
 | 
|---|
| 178 |         for (index = eth_protos_count(ð_globals.protos) - 1; index >= 0;
 | 
|---|
| 179 |             index--) {
 | 
|---|
| 180 |                 proto = eth_protos_get_index(ð_globals.protos, index);
 | 
|---|
| 181 |                 if (proto && proto->phone) {
 | 
|---|
| 182 |                         il_device_state_msg(proto->phone, device_id, state,
 | 
|---|
| 183 |                             proto->service);
 | 
|---|
| 184 |                 }
 | 
|---|
| 185 |         }
 | 
|---|
| 186 |         fibril_rwlock_read_unlock(ð_globals.protos_lock);
 | 
|---|
| 187 |         
 | 
|---|
| 188 |         return EOK;
 | 
|---|
| 189 | }
 | 
|---|
| 190 | 
 | 
|---|
| 191 | int nil_initialize(int net_phone)
 | 
|---|
| 192 | {
 | 
|---|
| 193 |         int rc;
 | 
|---|
| 194 | 
 | 
|---|
| 195 |         fibril_rwlock_initialize(ð_globals.devices_lock);
 | 
|---|
| 196 |         fibril_rwlock_initialize(ð_globals.protos_lock);
 | 
|---|
| 197 |         
 | 
|---|
| 198 |         fibril_rwlock_write_lock(ð_globals.devices_lock);
 | 
|---|
| 199 |         fibril_rwlock_write_lock(ð_globals.protos_lock);
 | 
|---|
| 200 |         eth_globals.net_phone = net_phone;
 | 
|---|
| 201 | 
 | 
|---|
| 202 |         eth_globals.broadcast_addr =
 | 
|---|
| 203 |             measured_string_create_bulk("\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ADDR);
 | 
|---|
| 204 |         if (!eth_globals.broadcast_addr) {
 | 
|---|
| 205 |                 rc = ENOMEM;
 | 
|---|
| 206 |                 goto out;
 | 
|---|
| 207 |         }
 | 
|---|
| 208 | 
 | 
|---|
| 209 |         rc = eth_devices_initialize(ð_globals.devices);
 | 
|---|
| 210 |         if (rc != EOK) {
 | 
|---|
| 211 |                 free(eth_globals.broadcast_addr);
 | 
|---|
| 212 |                 goto out;
 | 
|---|
| 213 |         }
 | 
|---|
| 214 | 
 | 
|---|
| 215 |         rc = eth_protos_initialize(ð_globals.protos);
 | 
|---|
| 216 |         if (rc != EOK) {
 | 
|---|
| 217 |                 free(eth_globals.broadcast_addr);
 | 
|---|
| 218 |                 eth_devices_destroy(ð_globals.devices);
 | 
|---|
| 219 |         }
 | 
|---|
| 220 | out:
 | 
|---|
| 221 |         fibril_rwlock_write_unlock(ð_globals.protos_lock);
 | 
|---|
| 222 |         fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 223 |         
 | 
|---|
| 224 |         return rc;
 | 
|---|
| 225 | }
 | 
|---|
| 226 | 
 | 
|---|
| 227 | /** Processes IPC messages from the registered device driver modules in an
 | 
|---|
| 228 |  * infinite loop.
 | 
|---|
| 229 |  *
 | 
|---|
| 230 |  * @param[in] iid       The message identifier.
 | 
|---|
| 231 |  * @param[in,out] icall The message parameters.
 | 
|---|
| 232 |  */
 | 
|---|
| 233 | static void eth_receiver(ipc_callid_t iid, ipc_call_t *icall)
 | 
|---|
| 234 | {
 | 
|---|
| 235 |         packet_t *packet;
 | 
|---|
| 236 |         int rc;
 | 
|---|
| 237 | 
 | 
|---|
| 238 |         while (true) {
 | 
|---|
| 239 |                 switch (IPC_GET_IMETHOD(*icall)) {
 | 
|---|
| 240 |                 case NET_NIL_DEVICE_STATE:
 | 
|---|
| 241 |                         nil_device_state_msg_local(0, IPC_GET_DEVICE(icall),
 | 
|---|
| 242 |                             IPC_GET_STATE(icall));
 | 
|---|
| 243 |                         ipc_answer_0(iid, EOK);
 | 
|---|
| 244 |                         break;
 | 
|---|
| 245 |                 case NET_NIL_RECEIVED:
 | 
|---|
| 246 |                         rc = packet_translate_remote(eth_globals.net_phone,
 | 
|---|
| 247 |                             &packet, IPC_GET_PACKET(icall));
 | 
|---|
| 248 |                         if (rc == EOK) {
 | 
|---|
| 249 |                                 rc = nil_received_msg_local(0,
 | 
|---|
| 250 |                                     IPC_GET_DEVICE(icall), packet, 0);
 | 
|---|
| 251 |                         }
 | 
|---|
| 252 |                         ipc_answer_0(iid, (sysarg_t) rc);
 | 
|---|
| 253 |                         break;
 | 
|---|
| 254 |                 default:
 | 
|---|
| 255 |                         ipc_answer_0(iid, (sysarg_t) ENOTSUP);
 | 
|---|
| 256 |                 }
 | 
|---|
| 257 |                 
 | 
|---|
| 258 |                 iid = async_get_call(icall);
 | 
|---|
| 259 |         }
 | 
|---|
| 260 | }
 | 
|---|
| 261 | 
 | 
|---|
| 262 | /** Registers new device or updates the MTU of an existing one.
 | 
|---|
| 263 |  *
 | 
|---|
| 264 |  * Determines the device local hardware address.
 | 
|---|
| 265 |  *
 | 
|---|
| 266 |  * @param[in] device_id The new device identifier.
 | 
|---|
| 267 |  * @param[in] service   The device driver service.
 | 
|---|
| 268 |  * @param[in] mtu       The device maximum transmission unit.
 | 
|---|
| 269 |  * @return              EOK on success.
 | 
|---|
| 270 |  * @return              EEXIST if the device with the different service exists.
 | 
|---|
| 271 |  * @return              ENOMEM if there is not enough memory left.
 | 
|---|
| 272 |  * @return              Other error codes as defined for the
 | 
|---|
| 273 |  *                      net_get_device_conf_req() function.
 | 
|---|
| 274 |  * @return              Other error codes as defined for the
 | 
|---|
| 275 |  *                      netif_bind_service() function.
 | 
|---|
| 276 |  * @return              Other error codes as defined for the
 | 
|---|
| 277 |  *                      netif_get_addr_req() function.
 | 
|---|
| 278 |  */
 | 
|---|
| 279 | static int eth_device_message(device_id_t device_id, services_t service,
 | 
|---|
| 280 |     size_t mtu)
 | 
|---|
| 281 | {
 | 
|---|
| 282 |         eth_device_t *device;
 | 
|---|
| 283 |         int index;
 | 
|---|
| 284 |         measured_string_t names[2] = {
 | 
|---|
| 285 |                 {
 | 
|---|
| 286 |                         (char *) "ETH_MODE",
 | 
|---|
| 287 |                         8
 | 
|---|
| 288 |                 },
 | 
|---|
| 289 |                 {
 | 
|---|
| 290 |                         (char *) "ETH_DUMMY",
 | 
|---|
| 291 |                         9
 | 
|---|
| 292 |                 }
 | 
|---|
| 293 |         };
 | 
|---|
| 294 |         measured_string_t *configuration;
 | 
|---|
| 295 |         size_t count = sizeof(names) / sizeof(measured_string_t);
 | 
|---|
| 296 |         char *data;
 | 
|---|
| 297 |         eth_proto_t *proto;
 | 
|---|
| 298 |         int rc;
 | 
|---|
| 299 | 
 | 
|---|
| 300 |         fibril_rwlock_write_lock(ð_globals.devices_lock);
 | 
|---|
| 301 |         /* An existing device? */
 | 
|---|
| 302 |         device = eth_devices_find(ð_globals.devices, device_id);
 | 
|---|
| 303 |         if (device) {
 | 
|---|
| 304 |                 if (device->service != service) {
 | 
|---|
| 305 |                         printf("Device %d already exists\n", device->device_id);
 | 
|---|
| 306 |                         fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 307 |                         return EEXIST;
 | 
|---|
| 308 |                 }
 | 
|---|
| 309 |                 
 | 
|---|
| 310 |                 /* Update mtu */
 | 
|---|
| 311 |                 if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
 | 
|---|
| 312 |                         device->mtu = mtu;
 | 
|---|
| 313 |                 else
 | 
|---|
| 314 |                         device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
 | 
|---|
| 315 |                 
 | 
|---|
| 316 |                 printf("Device %d already exists:\tMTU\t= %zu\n",
 | 
|---|
| 317 |                     device->device_id, device->mtu);
 | 
|---|
| 318 |                 fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 319 |                 
 | 
|---|
| 320 |                 /* Notify all upper layer modules */
 | 
|---|
| 321 |                 fibril_rwlock_read_lock(ð_globals.protos_lock);
 | 
|---|
| 322 |                 for (index = 0; index < eth_protos_count(ð_globals.protos);
 | 
|---|
| 323 |                     index++) {
 | 
|---|
| 324 |                         proto = eth_protos_get_index(ð_globals.protos,
 | 
|---|
| 325 |                             index);
 | 
|---|
| 326 |                         if (proto->phone) {
 | 
|---|
| 327 |                                 il_mtu_changed_msg(proto->phone,
 | 
|---|
| 328 |                                     device->device_id, device->mtu,
 | 
|---|
| 329 |                                     proto->service);
 | 
|---|
| 330 |                         }
 | 
|---|
| 331 |                 }
 | 
|---|
| 332 | 
 | 
|---|
| 333 |                 fibril_rwlock_read_unlock(ð_globals.protos_lock);
 | 
|---|
| 334 |                 return EOK;
 | 
|---|
| 335 |         }
 | 
|---|
| 336 |         
 | 
|---|
| 337 |         /* Create a new device */
 | 
|---|
| 338 |         device = (eth_device_t *) malloc(sizeof(eth_device_t));
 | 
|---|
| 339 |         if (!device)
 | 
|---|
| 340 |                 return ENOMEM;
 | 
|---|
| 341 | 
 | 
|---|
| 342 |         device->device_id = device_id;
 | 
|---|
| 343 |         device->service = service;
 | 
|---|
| 344 |         device->flags = 0;
 | 
|---|
| 345 |         if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
 | 
|---|
| 346 |                 device->mtu = mtu;
 | 
|---|
| 347 |         else
 | 
|---|
| 348 |                 device->mtu = ETH_MAX_TAGGED_CONTENT(device->flags);
 | 
|---|
| 349 | 
 | 
|---|
| 350 |         configuration = &names[0];
 | 
|---|
| 351 |         rc = net_get_device_conf_req(eth_globals.net_phone, device->device_id,
 | 
|---|
| 352 |             &configuration, count, &data);
 | 
|---|
| 353 |         if (rc != EOK) {
 | 
|---|
| 354 |                 fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 355 |                 free(device);
 | 
|---|
| 356 |                 return rc;
 | 
|---|
| 357 |         }
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         if (configuration) {
 | 
|---|
| 360 |                 if (!str_lcmp(configuration[0].value, "DIX",
 | 
|---|
| 361 |                     configuration[0].length)) {
 | 
|---|
| 362 |                         device->flags |= ETH_DIX;
 | 
|---|
| 363 |                 } else if(!str_lcmp(configuration[0].value, "8023_2_LSAP",
 | 
|---|
| 364 |                     configuration[0].length)) {
 | 
|---|
| 365 |                         device->flags |= ETH_8023_2_LSAP;
 | 
|---|
| 366 |                 } else {
 | 
|---|
| 367 |                         device->flags |= ETH_8023_2_SNAP;
 | 
|---|
| 368 |                 }
 | 
|---|
| 369 |                 
 | 
|---|
| 370 |                 if (configuration[1].value &&
 | 
|---|
| 371 |                     (configuration[1].value[0] == 'y')) {
 | 
|---|
| 372 |                         device->flags |= ETH_DUMMY;
 | 
|---|
| 373 |                 }
 | 
|---|
| 374 |                 net_free_settings(configuration, data);
 | 
|---|
| 375 |         } else {
 | 
|---|
| 376 |                 device->flags |= ETH_8023_2_SNAP;
 | 
|---|
| 377 |         }
 | 
|---|
| 378 |         
 | 
|---|
| 379 |         /* Bind the device driver */
 | 
|---|
| 380 |         device->phone = netif_bind_service(device->service, device->device_id,
 | 
|---|
| 381 |             SERVICE_ETHERNET, eth_receiver);
 | 
|---|
| 382 |         if (device->phone < 0) {
 | 
|---|
| 383 |                 fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 384 |                 free(device);
 | 
|---|
| 385 |                 return device->phone;
 | 
|---|
| 386 |         }
 | 
|---|
| 387 |         
 | 
|---|
| 388 |         /* Get hardware address */
 | 
|---|
| 389 |         rc = netif_get_addr_req(device->phone, device->device_id, &device->addr,
 | 
|---|
| 390 |             &device->addr_data);
 | 
|---|
| 391 |         if (rc != EOK) {
 | 
|---|
| 392 |                 fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 393 |                 free(device);
 | 
|---|
| 394 |                 return rc;
 | 
|---|
| 395 |         }
 | 
|---|
| 396 |         
 | 
|---|
| 397 |         /* Add to the cache */
 | 
|---|
| 398 |         index = eth_devices_add(ð_globals.devices, device->device_id,
 | 
|---|
| 399 |             device);
 | 
|---|
| 400 |         if (index < 0) {
 | 
|---|
| 401 |                 fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 402 |                 free(device->addr);
 | 
|---|
| 403 |                 free(device->addr_data);
 | 
|---|
| 404 |                 free(device);
 | 
|---|
| 405 |                 return index;
 | 
|---|
| 406 |         }
 | 
|---|
| 407 |         
 | 
|---|
| 408 |         printf("%s: Device registered (id: %d, service: %d: mtu: %zu, "
 | 
|---|
| 409 |             "mac: %x:%x:%x:%x:%x:%x, flags: 0x%x)\n",
 | 
|---|
| 410 |             NAME, device->device_id, device->service, device->mtu,
 | 
|---|
| 411 |             device->addr_data[0], device->addr_data[1],
 | 
|---|
| 412 |             device->addr_data[2], device->addr_data[3],
 | 
|---|
| 413 |             device->addr_data[4], device->addr_data[5], device->flags);
 | 
|---|
| 414 | 
 | 
|---|
| 415 |         fibril_rwlock_write_unlock(ð_globals.devices_lock);
 | 
|---|
| 416 |         return EOK;
 | 
|---|
| 417 | }
 | 
|---|
| 418 | 
 | 
|---|
| 419 | /** Processes the received packet and chooses the target registered module.
 | 
|---|
| 420 |  *
 | 
|---|
| 421 |  * @param[in] flags     The device flags.
 | 
|---|
| 422 |  * @param[in] packet    The packet.
 | 
|---|
| 423 |  * @return              The target registered module.
 | 
|---|
| 424 |  * @return              NULL if the packet is not long enough.
 | 
|---|
| 425 |  * @return              NULL if the packet is too long.
 | 
|---|
| 426 |  * @return              NULL if the raw ethernet protocol is used.
 | 
|---|
| 427 |  * @return              NULL if the dummy device FCS checksum is invalid.
 | 
|---|
| 428 |  * @return              NULL if the packet address length is not big enough.
 | 
|---|
| 429 |  */
 | 
|---|
| 430 | static eth_proto_t *eth_process_packet(int flags, packet_t *packet)
 | 
|---|
| 431 | {
 | 
|---|
| 432 |         eth_header_snap_t *header;
 | 
|---|
| 433 |         size_t length;
 | 
|---|
| 434 |         eth_type_t type;
 | 
|---|
| 435 |         size_t prefix;
 | 
|---|
| 436 |         size_t suffix;
 | 
|---|
| 437 |         eth_fcs_t *fcs;
 | 
|---|
| 438 |         uint8_t *data;
 | 
|---|
| 439 |         int rc;
 | 
|---|
| 440 | 
 | 
|---|
| 441 |         length = packet_get_data_length(packet);
 | 
|---|
| 442 |         
 | 
|---|
| 443 |         if (IS_DUMMY(flags))
 | 
|---|
| 444 |                 packet_trim(packet, sizeof(eth_preamble_t), 0);
 | 
|---|
| 445 |         if (length < sizeof(eth_header_t) + ETH_MIN_CONTENT +
 | 
|---|
| 446 |             (IS_DUMMY(flags) ? ETH_SUFFIX : 0))
 | 
|---|
| 447 |                 return NULL;
 | 
|---|
| 448 |         
 | 
|---|
| 449 |         data = packet_get_data(packet);
 | 
|---|
| 450 |         header = (eth_header_snap_t *) data;
 | 
|---|
| 451 |         type = ntohs(header->header.ethertype);
 | 
|---|
| 452 |         
 | 
|---|
| 453 |         if (type >= ETH_MIN_PROTO) {
 | 
|---|
| 454 |                 /* DIX Ethernet */
 | 
|---|
| 455 |                 prefix = sizeof(eth_header_t);
 | 
|---|
| 456 |                 suffix = 0;
 | 
|---|
| 457 |                 fcs = (eth_fcs_t *) data + length - sizeof(eth_fcs_t);
 | 
|---|
| 458 |                 length -= sizeof(eth_fcs_t);
 | 
|---|
| 459 |         } else if(type <= ETH_MAX_CONTENT) {
 | 
|---|
| 460 |                 /* Translate "LSAP" values */
 | 
|---|
| 461 |                 if ((header->lsap.dsap == ETH_LSAP_GLSAP) &&
 | 
|---|
| 462 |                     (header->lsap.ssap == ETH_LSAP_GLSAP)) {
 | 
|---|
| 463 |                         /* Raw packet -- discard */
 | 
|---|
| 464 |                         return NULL;
 | 
|---|
| 465 |                 } else if((header->lsap.dsap == ETH_LSAP_SNAP) &&
 | 
|---|
| 466 |                     (header->lsap.ssap == ETH_LSAP_SNAP)) {
 | 
|---|
| 467 |                         /*
 | 
|---|
| 468 |                          * IEEE 802.3 + 802.2 + LSAP + SNAP
 | 
|---|
| 469 |                          * organization code not supported
 | 
|---|
| 470 |                          */
 | 
|---|
| 471 |                         type = ntohs(header->snap.ethertype);
 | 
|---|
| 472 |                         prefix = sizeof(eth_header_t) +
 | 
|---|
| 473 |                             sizeof(eth_header_lsap_t) +
 | 
|---|
| 474 |                             sizeof(eth_header_snap_t);
 | 
|---|
| 475 |                 } else {
 | 
|---|
| 476 |                         /* IEEE 802.3 + 802.2 LSAP */
 | 
|---|
| 477 |                         type = lsap_map(header->lsap.dsap);
 | 
|---|
| 478 |                         prefix = sizeof(eth_header_t) +
 | 
|---|
| 479 |                             sizeof(eth_header_lsap_t);
 | 
|---|
| 480 |                 }
 | 
|---|
| 481 | 
 | 
|---|
| 482 |                 suffix = (type < ETH_MIN_CONTENT) ? ETH_MIN_CONTENT - type : 0U;
 | 
|---|
| 483 |                 fcs = (eth_fcs_t *) data + prefix + type + suffix;
 | 
|---|
| 484 |                 suffix += length - prefix - type;
 | 
|---|
| 485 |                 length = prefix + type + suffix;
 | 
|---|
| 486 |         } else {
 | 
|---|
| 487 |                 /* Invalid length/type, should not occur */
 | 
|---|
| 488 |                 return NULL;
 | 
|---|
| 489 |         }
 | 
|---|
| 490 |         
 | 
|---|
| 491 |         if (IS_DUMMY(flags)) {
 | 
|---|
| 492 |                 if (~compute_crc32(~0U, data, length * 8) != ntohl(*fcs))
 | 
|---|
| 493 |                         return NULL;
 | 
|---|
| 494 |                 suffix += sizeof(eth_fcs_t);
 | 
|---|
| 495 |         }
 | 
|---|
| 496 |         
 | 
|---|
| 497 |         rc = packet_set_addr(packet, header->header.source_address,
 | 
|---|
| 498 |             header->header.destination_address, ETH_ADDR);
 | 
|---|
| 499 |         if (rc != EOK)
 | 
|---|
| 500 |                 return NULL;
 | 
|---|
| 501 | 
 | 
|---|
| 502 |         rc = packet_trim(packet, prefix, suffix);
 | 
|---|
| 503 |         if (rc != EOK)
 | 
|---|
| 504 |                 return NULL;
 | 
|---|
| 505 |         
 | 
|---|
| 506 |         return eth_protos_find(ð_globals.protos, type);
 | 
|---|
| 507 | }
 | 
|---|
| 508 | 
 | 
|---|
| 509 | int nil_received_msg_local(int nil_phone, device_id_t device_id,
 | 
|---|
| 510 |     packet_t *packet, services_t target)
 | 
|---|
| 511 | {
 | 
|---|
| 512 |         eth_proto_t *proto;
 | 
|---|
| 513 |         packet_t *next;
 | 
|---|
| 514 |         eth_device_t *device;
 | 
|---|
| 515 |         int flags;
 | 
|---|
| 516 | 
 | 
|---|
| 517 |         fibril_rwlock_read_lock(ð_globals.devices_lock);
 | 
|---|
| 518 |         device = eth_devices_find(ð_globals.devices, device_id);
 | 
|---|
| 519 |         if (!device) {
 | 
|---|
| 520 |                 fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 521 |                 return ENOENT;
 | 
|---|
| 522 |         }
 | 
|---|
| 523 | 
 | 
|---|
| 524 |         flags = device->flags;
 | 
|---|
| 525 |         fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 526 |         
 | 
|---|
| 527 |         fibril_rwlock_read_lock(ð_globals.protos_lock);
 | 
|---|
| 528 |         do {
 | 
|---|
| 529 |                 next = pq_detach(packet);
 | 
|---|
| 530 |                 proto = eth_process_packet(flags, packet);
 | 
|---|
| 531 |                 if (proto) {
 | 
|---|
| 532 |                         il_received_msg(proto->phone, device_id, packet,
 | 
|---|
| 533 |                             proto->service);
 | 
|---|
| 534 |                 } else {
 | 
|---|
| 535 |                         // drop invalid/unknown
 | 
|---|
| 536 |                         pq_release_remote(eth_globals.net_phone,
 | 
|---|
| 537 |                             packet_get_id(packet));
 | 
|---|
| 538 |                 }
 | 
|---|
| 539 |                 packet = next;
 | 
|---|
| 540 |         } while(packet);
 | 
|---|
| 541 | 
 | 
|---|
| 542 |         fibril_rwlock_read_unlock(ð_globals.protos_lock);
 | 
|---|
| 543 |         return EOK;
 | 
|---|
| 544 | }
 | 
|---|
| 545 | 
 | 
|---|
| 546 | /** Returns the device packet dimensions for sending.
 | 
|---|
| 547 |  *
 | 
|---|
| 548 |  * @param[in] device_id The device identifier.
 | 
|---|
| 549 |  * @param[out] addr_len The minimum reserved address length.
 | 
|---|
| 550 |  * @param[out] prefix   The minimum reserved prefix size.
 | 
|---|
| 551 |  * @param[out] content  The maximum content size.
 | 
|---|
| 552 |  * @param[out] suffix   The minimum reserved suffix size.
 | 
|---|
| 553 |  * @return              EOK on success.
 | 
|---|
| 554 |  * @return              EBADMEM if either one of the parameters is NULL.
 | 
|---|
| 555 |  * @return              ENOENT if there is no such device.
 | 
|---|
| 556 |  */
 | 
|---|
| 557 | static int eth_packet_space_message(device_id_t device_id, size_t *addr_len,
 | 
|---|
| 558 |     size_t *prefix, size_t *content, size_t *suffix)
 | 
|---|
| 559 | {
 | 
|---|
| 560 |         eth_device_t *device;
 | 
|---|
| 561 | 
 | 
|---|
| 562 |         if (!addr_len || !prefix || !content || !suffix)
 | 
|---|
| 563 |                 return EBADMEM;
 | 
|---|
| 564 |         
 | 
|---|
| 565 |         fibril_rwlock_read_lock(ð_globals.devices_lock);
 | 
|---|
| 566 |         device = eth_devices_find(ð_globals.devices, device_id);
 | 
|---|
| 567 |         if (!device) {
 | 
|---|
| 568 |                 fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 569 |                 return ENOENT;
 | 
|---|
| 570 |         }
 | 
|---|
| 571 | 
 | 
|---|
| 572 |         *content = device->mtu;
 | 
|---|
| 573 |         fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 574 |         
 | 
|---|
| 575 |         *addr_len = ETH_ADDR;
 | 
|---|
| 576 |         *prefix = ETH_PREFIX;
 | 
|---|
| 577 |         *suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
 | 
|---|
| 578 | 
 | 
|---|
| 579 |         return EOK;
 | 
|---|
| 580 | }
 | 
|---|
| 581 | 
 | 
|---|
| 582 | /** Returns the device hardware address.
 | 
|---|
| 583 |  *
 | 
|---|
| 584 |  * @param[in] device_id The device identifier.
 | 
|---|
| 585 |  * @param[in] type      Type of the desired address.
 | 
|---|
| 586 |  * @param[out] address  The device hardware address.
 | 
|---|
| 587 |  * @return              EOK on success.
 | 
|---|
| 588 |  * @return              EBADMEM if the address parameter is NULL.
 | 
|---|
| 589 |  * @return              ENOENT if there no such device.
 | 
|---|
| 590 |  */
 | 
|---|
| 591 | static int eth_addr_message(device_id_t device_id, eth_addr_type_t type,
 | 
|---|
| 592 |     measured_string_t **address)
 | 
|---|
| 593 | {
 | 
|---|
| 594 |         eth_device_t *device;
 | 
|---|
| 595 | 
 | 
|---|
| 596 |         if (!address)
 | 
|---|
| 597 |                 return EBADMEM;
 | 
|---|
| 598 | 
 | 
|---|
| 599 |         if (type == ETH_BROADCAST_ADDR) {
 | 
|---|
| 600 |                 *address = eth_globals.broadcast_addr;
 | 
|---|
| 601 |         } else {
 | 
|---|
| 602 |                 fibril_rwlock_read_lock(ð_globals.devices_lock);
 | 
|---|
| 603 |                 device = eth_devices_find(ð_globals.devices, device_id);
 | 
|---|
| 604 |                 if (!device) {
 | 
|---|
| 605 |                         fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 606 |                         return ENOENT;
 | 
|---|
| 607 |                 }
 | 
|---|
| 608 |                 *address = device->addr;
 | 
|---|
| 609 |                 fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 610 |         }
 | 
|---|
| 611 |         
 | 
|---|
| 612 |         return (*address) ? EOK : ENOENT;
 | 
|---|
| 613 | }
 | 
|---|
| 614 | 
 | 
|---|
| 615 | /** Registers receiving module service.
 | 
|---|
| 616 |  *
 | 
|---|
| 617 |  * Passes received packets for this service.
 | 
|---|
| 618 |  *
 | 
|---|
| 619 |  * @param[in] service   The module service.
 | 
|---|
| 620 |  * @param[in] phone     The service phone.
 | 
|---|
| 621 |  * @return              EOK on success.
 | 
|---|
| 622 |  * @return              ENOENT if the service is not known.
 | 
|---|
| 623 |  * @return              ENOMEM if there is not enough memory left.
 | 
|---|
| 624 |  */
 | 
|---|
| 625 | static int eth_register_message(services_t service, int phone)
 | 
|---|
| 626 | {
 | 
|---|
| 627 |         eth_proto_t *proto;
 | 
|---|
| 628 |         int protocol;
 | 
|---|
| 629 |         int index;
 | 
|---|
| 630 | 
 | 
|---|
| 631 |         protocol = protocol_map(SERVICE_ETHERNET, service);
 | 
|---|
| 632 |         if (!protocol)
 | 
|---|
| 633 |                 return ENOENT;
 | 
|---|
| 634 | 
 | 
|---|
| 635 |         fibril_rwlock_write_lock(ð_globals.protos_lock);
 | 
|---|
| 636 |         proto = eth_protos_find(ð_globals.protos, protocol);
 | 
|---|
| 637 |         if (proto) {
 | 
|---|
| 638 |                 proto->phone = phone;
 | 
|---|
| 639 |                 fibril_rwlock_write_unlock(ð_globals.protos_lock);
 | 
|---|
| 640 |                 return EOK;
 | 
|---|
| 641 |         } else {
 | 
|---|
| 642 |                 proto = (eth_proto_t *) malloc(sizeof(eth_proto_t));
 | 
|---|
| 643 |                 if (!proto) {
 | 
|---|
| 644 |                         fibril_rwlock_write_unlock(ð_globals.protos_lock);
 | 
|---|
| 645 |                         return ENOMEM;
 | 
|---|
| 646 |                 }
 | 
|---|
| 647 | 
 | 
|---|
| 648 |                 proto->service = service;
 | 
|---|
| 649 |                 proto->protocol = protocol;
 | 
|---|
| 650 |                 proto->phone = phone;
 | 
|---|
| 651 | 
 | 
|---|
| 652 |                 index = eth_protos_add(ð_globals.protos, protocol, proto);
 | 
|---|
| 653 |                 if (index < 0) {
 | 
|---|
| 654 |                         fibril_rwlock_write_unlock(ð_globals.protos_lock);
 | 
|---|
| 655 |                         free(proto);
 | 
|---|
| 656 |                         return index;
 | 
|---|
| 657 |                 }
 | 
|---|
| 658 |         }
 | 
|---|
| 659 |         
 | 
|---|
| 660 |         printf("%s: Protocol registered (protocol: %d, service: %d, phone: "
 | 
|---|
| 661 |             "%d)\n", NAME, proto->protocol, proto->service, proto->phone);
 | 
|---|
| 662 |         
 | 
|---|
| 663 |         fibril_rwlock_write_unlock(ð_globals.protos_lock);
 | 
|---|
| 664 |         return EOK;
 | 
|---|
| 665 | }
 | 
|---|
| 666 | 
 | 
|---|
| 667 | /** Prepares the packet for sending.
 | 
|---|
| 668 |  *
 | 
|---|
| 669 |  * @param[in] flags     The device flags.
 | 
|---|
| 670 |  * @param[in] packet    The packet.
 | 
|---|
| 671 |  * @param[in] src_addr  The source hardware address.
 | 
|---|
| 672 |  * @param[in] ethertype The ethernet protocol type.
 | 
|---|
| 673 |  * @param[in] mtu       The device maximum transmission unit.
 | 
|---|
| 674 |  * @return              EOK on success.
 | 
|---|
| 675 |  * @return              EINVAL if the packet addresses length is not long
 | 
|---|
| 676 |  *                      enough.
 | 
|---|
| 677 |  * @return              EINVAL if the packet is bigger than the device MTU.
 | 
|---|
| 678 |  * @return              ENOMEM if there is not enough memory in the packet.
 | 
|---|
| 679 |  */
 | 
|---|
| 680 | static int
 | 
|---|
| 681 | eth_prepare_packet(int flags, packet_t *packet, uint8_t *src_addr, int ethertype,
 | 
|---|
| 682 |     size_t mtu)
 | 
|---|
| 683 | {
 | 
|---|
| 684 |         eth_header_snap_t *header;
 | 
|---|
| 685 |         eth_header_lsap_t *header_lsap;
 | 
|---|
| 686 |         eth_header_t *header_dix;
 | 
|---|
| 687 |         eth_fcs_t *fcs;
 | 
|---|
| 688 |         uint8_t *src;
 | 
|---|
| 689 |         uint8_t *dest;
 | 
|---|
| 690 |         size_t length;
 | 
|---|
| 691 |         int i;
 | 
|---|
| 692 |         void *padding;
 | 
|---|
| 693 |         eth_preamble_t *preamble;
 | 
|---|
| 694 | 
 | 
|---|
| 695 |         i = packet_get_addr(packet, &src, &dest);
 | 
|---|
| 696 |         if (i < 0)
 | 
|---|
| 697 |                 return i;
 | 
|---|
| 698 |         if (i != ETH_ADDR)
 | 
|---|
| 699 |                 return EINVAL;
 | 
|---|
| 700 | 
 | 
|---|
| 701 |         length = packet_get_data_length(packet);
 | 
|---|
| 702 |         if (length > mtu)
 | 
|---|
| 703 |                 return EINVAL;
 | 
|---|
| 704 |         
 | 
|---|
| 705 |         if (length < ETH_MIN_TAGGED_CONTENT(flags)) {
 | 
|---|
| 706 |                 padding = packet_suffix(packet,
 | 
|---|
| 707 |                     ETH_MIN_TAGGED_CONTENT(flags) - length);
 | 
|---|
| 708 |                 if (!padding)
 | 
|---|
| 709 |                         return ENOMEM;
 | 
|---|
| 710 | 
 | 
|---|
| 711 |                 bzero(padding, ETH_MIN_TAGGED_CONTENT(flags) - length);
 | 
|---|
| 712 |         }
 | 
|---|
| 713 |         
 | 
|---|
| 714 |         if (IS_DIX(flags)) {
 | 
|---|
| 715 |                 header_dix = PACKET_PREFIX(packet, eth_header_t);
 | 
|---|
| 716 |                 if (!header_dix)
 | 
|---|
| 717 |                         return ENOMEM;
 | 
|---|
| 718 |                 
 | 
|---|
| 719 |                 header_dix->ethertype = (uint16_t) ethertype;
 | 
|---|
| 720 |                 memcpy(header_dix->source_address, src_addr, ETH_ADDR);
 | 
|---|
| 721 |                 memcpy(header_dix->destination_address, dest, ETH_ADDR);
 | 
|---|
| 722 |                 src = &header_dix->destination_address[0];
 | 
|---|
| 723 |         } else if(IS_8023_2_LSAP(flags)) {
 | 
|---|
| 724 |                 header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
 | 
|---|
| 725 |                 if (!header_lsap)
 | 
|---|
| 726 |                         return ENOMEM;
 | 
|---|
| 727 |                 
 | 
|---|
| 728 |                 header_lsap->header.ethertype = htons(length +
 | 
|---|
| 729 |                     sizeof(eth_header_lsap_t));
 | 
|---|
| 730 |                 header_lsap->lsap.dsap = lsap_unmap(ntohs(ethertype));
 | 
|---|
| 731 |                 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
 | 
|---|
| 732 |                 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
 | 
|---|
| 733 |                 memcpy(header_lsap->header.source_address, src_addr, ETH_ADDR);
 | 
|---|
| 734 |                 memcpy(header_lsap->header.destination_address, dest, ETH_ADDR);
 | 
|---|
| 735 |                 src = &header_lsap->header.destination_address[0];
 | 
|---|
| 736 |         } else if(IS_8023_2_SNAP(flags)) {
 | 
|---|
| 737 |                 header = PACKET_PREFIX(packet, eth_header_snap_t);
 | 
|---|
| 738 |                 if (!header)
 | 
|---|
| 739 |                         return ENOMEM;
 | 
|---|
| 740 |                 
 | 
|---|
| 741 |                 header->header.ethertype = htons(length +
 | 
|---|
| 742 |                     sizeof(eth_header_lsap_t) + sizeof(eth_header_snap_t));
 | 
|---|
| 743 |                 header->lsap.dsap = (uint16_t) ETH_LSAP_SNAP;
 | 
|---|
| 744 |                 header->lsap.ssap = header->lsap.dsap;
 | 
|---|
| 745 |                 header->lsap.ctrl = IEEE_8023_2_UI;
 | 
|---|
| 746 |                 
 | 
|---|
| 747 |                 for (i = 0; i < 3; ++ i)
 | 
|---|
| 748 |                         header->snap.protocol[i] = 0;
 | 
|---|
| 749 |                 
 | 
|---|
| 750 |                 header->snap.ethertype = (uint16_t) ethertype;
 | 
|---|
| 751 |                 memcpy(header->header.source_address, src_addr, ETH_ADDR);
 | 
|---|
| 752 |                 memcpy(header->header.destination_address, dest, ETH_ADDR);
 | 
|---|
| 753 |                 src = &header->header.destination_address[0];
 | 
|---|
| 754 |         }
 | 
|---|
| 755 |         
 | 
|---|
| 756 |         if (IS_DUMMY(flags)) {
 | 
|---|
| 757 |                 preamble = PACKET_PREFIX(packet, eth_preamble_t);
 | 
|---|
| 758 |                 if (!preamble)
 | 
|---|
| 759 |                         return ENOMEM;
 | 
|---|
| 760 |                 
 | 
|---|
| 761 |                 for (i = 0; i < 7; ++ i)
 | 
|---|
| 762 |                         preamble->preamble[i] = ETH_PREAMBLE;
 | 
|---|
| 763 |                 
 | 
|---|
| 764 |                 preamble->sfd = ETH_SFD;
 | 
|---|
| 765 |                 
 | 
|---|
| 766 |                 fcs = PACKET_SUFFIX(packet, eth_fcs_t);
 | 
|---|
| 767 |                 if (!fcs)
 | 
|---|
| 768 |                         return ENOMEM;
 | 
|---|
| 769 | 
 | 
|---|
| 770 |                 *fcs = htonl(~compute_crc32(~0U, src, length * 8));
 | 
|---|
| 771 |         }
 | 
|---|
| 772 |         
 | 
|---|
| 773 |         return EOK;
 | 
|---|
| 774 | }
 | 
|---|
| 775 | 
 | 
|---|
| 776 | /** Sends the packet queue.
 | 
|---|
| 777 |  *
 | 
|---|
| 778 |  * Sends only packet successfully processed by the eth_prepare_packet()
 | 
|---|
| 779 |  * function.
 | 
|---|
| 780 |  *
 | 
|---|
| 781 |  * @param[in] device_id The device identifier.
 | 
|---|
| 782 |  * @param[in] packet    The packet queue.
 | 
|---|
| 783 |  * @param[in] sender    The sending module service.
 | 
|---|
| 784 |  * @return              EOK on success.
 | 
|---|
| 785 |  * @return              ENOENT if there no such device.
 | 
|---|
| 786 |  * @return              EINVAL if the service parameter is not known.
 | 
|---|
| 787 |  */
 | 
|---|
| 788 | static int eth_send_message(device_id_t device_id, packet_t *packet,
 | 
|---|
| 789 |     services_t sender)
 | 
|---|
| 790 | {
 | 
|---|
| 791 |         eth_device_t *device;
 | 
|---|
| 792 |         packet_t *next;
 | 
|---|
| 793 |         packet_t *tmp;
 | 
|---|
| 794 |         int ethertype;
 | 
|---|
| 795 |         int rc;
 | 
|---|
| 796 | 
 | 
|---|
| 797 |         ethertype = htons(protocol_map(SERVICE_ETHERNET, sender));
 | 
|---|
| 798 |         if (!ethertype) {
 | 
|---|
| 799 |                 pq_release_remote(eth_globals.net_phone, packet_get_id(packet));
 | 
|---|
| 800 |                 return EINVAL;
 | 
|---|
| 801 |         }
 | 
|---|
| 802 |         
 | 
|---|
| 803 |         fibril_rwlock_read_lock(ð_globals.devices_lock);
 | 
|---|
| 804 |         device = eth_devices_find(ð_globals.devices, device_id);
 | 
|---|
| 805 |         if (!device) {
 | 
|---|
| 806 |                 fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 807 |                 return ENOENT;
 | 
|---|
| 808 |         }
 | 
|---|
| 809 |         
 | 
|---|
| 810 |         /* Process packet queue */
 | 
|---|
| 811 |         next = packet;
 | 
|---|
| 812 |         do {
 | 
|---|
| 813 |                 rc = eth_prepare_packet(device->flags, next,
 | 
|---|
| 814 |                     (uint8_t *) device->addr->value, ethertype, device->mtu);
 | 
|---|
| 815 |                 if (rc != EOK) {
 | 
|---|
| 816 |                         /* Release invalid packet */
 | 
|---|
| 817 |                         tmp = pq_detach(next);
 | 
|---|
| 818 |                         if (next == packet)
 | 
|---|
| 819 |                                 packet = tmp;
 | 
|---|
| 820 |                         pq_release_remote(eth_globals.net_phone,
 | 
|---|
| 821 |                             packet_get_id(next));
 | 
|---|
| 822 |                         next = tmp;
 | 
|---|
| 823 |                 } else {
 | 
|---|
| 824 |                         next = pq_next(next);
 | 
|---|
| 825 |                 }
 | 
|---|
| 826 |         } while(next);
 | 
|---|
| 827 |         
 | 
|---|
| 828 |         /* Send packet queue */
 | 
|---|
| 829 |         if (packet) {
 | 
|---|
| 830 |                 netif_send_msg(device->phone, device_id, packet,
 | 
|---|
| 831 |                     SERVICE_ETHERNET);
 | 
|---|
| 832 |         }
 | 
|---|
| 833 | 
 | 
|---|
| 834 |         fibril_rwlock_read_unlock(ð_globals.devices_lock);
 | 
|---|
| 835 |         return EOK;
 | 
|---|
| 836 | }
 | 
|---|
| 837 | 
 | 
|---|
| 838 | int nil_message_standalone(const char *name, ipc_callid_t callid,
 | 
|---|
| 839 |     ipc_call_t *call, ipc_call_t *answer, int *answer_count)
 | 
|---|
| 840 | {
 | 
|---|
| 841 |         measured_string_t *address;
 | 
|---|
| 842 |         packet_t *packet;
 | 
|---|
| 843 |         size_t addrlen;
 | 
|---|
| 844 |         size_t prefix;
 | 
|---|
| 845 |         size_t suffix;
 | 
|---|
| 846 |         size_t content;
 | 
|---|
| 847 |         int rc;
 | 
|---|
| 848 |         
 | 
|---|
| 849 |         *answer_count = 0;
 | 
|---|
| 850 |         switch (IPC_GET_IMETHOD(*call)) {
 | 
|---|
| 851 |         case IPC_M_PHONE_HUNGUP:
 | 
|---|
| 852 |                 return EOK;
 | 
|---|
| 853 |         
 | 
|---|
| 854 |         case NET_NIL_DEVICE:
 | 
|---|
| 855 |                 return eth_device_message(IPC_GET_DEVICE(call),
 | 
|---|
| 856 |                     IPC_GET_SERVICE(call), IPC_GET_MTU(call));
 | 
|---|
| 857 |         case NET_NIL_SEND:
 | 
|---|
| 858 |                 rc = packet_translate_remote(eth_globals.net_phone, &packet,
 | 
|---|
| 859 |                     IPC_GET_PACKET(call));
 | 
|---|
| 860 |                 if (rc != EOK)
 | 
|---|
| 861 |                         return rc;
 | 
|---|
| 862 |                 return eth_send_message(IPC_GET_DEVICE(call), packet,
 | 
|---|
| 863 |                     IPC_GET_SERVICE(call));
 | 
|---|
| 864 |         case NET_NIL_PACKET_SPACE:
 | 
|---|
| 865 |                 rc = eth_packet_space_message(IPC_GET_DEVICE(call), &addrlen,
 | 
|---|
| 866 |                     &prefix, &content, &suffix);
 | 
|---|
| 867 |                 if (rc != EOK)
 | 
|---|
| 868 |                         return rc;
 | 
|---|
| 869 |                 IPC_SET_ADDR(answer, addrlen);
 | 
|---|
| 870 |                 IPC_SET_PREFIX(answer, prefix);
 | 
|---|
| 871 |                 IPC_SET_CONTENT(answer, content);
 | 
|---|
| 872 |                 IPC_SET_SUFFIX(answer, suffix);
 | 
|---|
| 873 |                 *answer_count = 4;
 | 
|---|
| 874 |                 return EOK;
 | 
|---|
| 875 |         case NET_NIL_ADDR:
 | 
|---|
| 876 |                 rc = eth_addr_message(IPC_GET_DEVICE(call), ETH_LOCAL_ADDR,
 | 
|---|
| 877 |                     &address);
 | 
|---|
| 878 |                 if (rc != EOK)
 | 
|---|
| 879 |                         return rc;
 | 
|---|
| 880 |                 return measured_strings_reply(address, 1);
 | 
|---|
| 881 |         case NET_NIL_BROADCAST_ADDR:
 | 
|---|
| 882 |                 rc = eth_addr_message(IPC_GET_DEVICE(call), ETH_BROADCAST_ADDR,
 | 
|---|
| 883 |                     &address);
 | 
|---|
| 884 |                 if (rc != EOK)
 | 
|---|
| 885 |                         return EOK;
 | 
|---|
| 886 |                 return measured_strings_reply(address, 1);
 | 
|---|
| 887 |         case IPC_M_CONNECT_TO_ME:
 | 
|---|
| 888 |                 return eth_register_message(NIL_GET_PROTO(call),
 | 
|---|
| 889 |                     IPC_GET_PHONE(call));
 | 
|---|
| 890 |         }
 | 
|---|
| 891 |         
 | 
|---|
| 892 |         return ENOTSUP;
 | 
|---|
| 893 | }
 | 
|---|
| 894 | 
 | 
|---|
| 895 | /** Default thread for new connections.
 | 
|---|
| 896 |  *
 | 
|---|
| 897 |  * @param[in] iid       The initial message identifier.
 | 
|---|
| 898 |  * @param[in] icall     The initial message call structure.
 | 
|---|
| 899 |  */
 | 
|---|
| 900 | static void nil_client_connection(ipc_callid_t iid, ipc_call_t *icall)
 | 
|---|
| 901 | {
 | 
|---|
| 902 |         /*
 | 
|---|
| 903 |          * Accept the connection
 | 
|---|
| 904 |          *  - Answer the first IPC_M_CONNECT_ME_TO call.
 | 
|---|
| 905 |          */
 | 
|---|
| 906 |         ipc_answer_0(iid, EOK);
 | 
|---|
| 907 |         
 | 
|---|
| 908 |         while (true) {
 | 
|---|
| 909 |                 ipc_call_t answer;
 | 
|---|
| 910 |                 int answer_count;
 | 
|---|
| 911 |                 
 | 
|---|
| 912 |                 /* Clear the answer structure */
 | 
|---|
| 913 |                 refresh_answer(&answer, &answer_count);
 | 
|---|
| 914 |                 
 | 
|---|
| 915 |                 /* Fetch the next message */
 | 
|---|
| 916 |                 ipc_call_t call;
 | 
|---|
| 917 |                 ipc_callid_t callid = async_get_call(&call);
 | 
|---|
| 918 |                 
 | 
|---|
| 919 |                 /* Process the message */
 | 
|---|
| 920 |                 int res = nil_module_message_standalone(NAME, callid, &call,
 | 
|---|
| 921 |                     &answer, &answer_count);
 | 
|---|
| 922 |                 
 | 
|---|
| 923 |                 /*
 | 
|---|
| 924 |                  * End if told to either by the message or the processing
 | 
|---|
| 925 |                  * result.
 | 
|---|
| 926 |                  */
 | 
|---|
| 927 |                 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
 | 
|---|
| 928 |                     (res == EHANGUP))
 | 
|---|
| 929 |                         return;
 | 
|---|
| 930 |                 
 | 
|---|
| 931 |                 /* Answer the message */
 | 
|---|
| 932 |                 answer_call(callid, res, &answer, answer_count);
 | 
|---|
| 933 |         }
 | 
|---|
| 934 | }
 | 
|---|
| 935 | 
 | 
|---|
| 936 | int main(int argc, char *argv[])
 | 
|---|
| 937 | {
 | 
|---|
| 938 |         int rc;
 | 
|---|
| 939 |         
 | 
|---|
| 940 |         /* Start the module */
 | 
|---|
| 941 |         rc = nil_module_start_standalone(nil_client_connection);
 | 
|---|
| 942 |         return rc;
 | 
|---|
| 943 | }
 | 
|---|
| 944 | 
 | 
|---|
| 945 | /** @}
 | 
|---|
| 946 |  */
 | 
|---|