Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/inetsrv/inet_link.c

    r3e6a98c5 rb417559  
    4343#include <stdlib.h>
    4444#include <str.h>
    45 
     45#include <net/socket_codes.h>
    4646#include "addrobj.h"
    4747#include "inetsrv.h"
     
    4949#include "pdu.h"
    5050
    51 static int inet_link_open(service_id_t sid);
    52 static int inet_iplink_recv(iplink_t *ilink, iplink_sdu_t *sdu);
     51static bool first_link = true;
     52static bool first_link6 = true;
     53
     54static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
     55static uint16_t ip_ident = 0;
     56
     57static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, uint16_t);
     58static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
    5359
    5460static iplink_ev_ops_t inet_iplink_ev_ops = {
     
    5662};
    5763
    58 static LIST_INITIALIZE(inet_link_list);
    59 static FIBRIL_MUTEX_INITIALIZE(inet_discovery_lock);
    60 
    61 static int inet_iplink_recv(iplink_t *iplink, iplink_sdu_t *sdu)
    62 {
     64static LIST_INITIALIZE(inet_links);
     65static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
     66
     67static addr128_t link_local_node_ip =
     68    {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0};
     69
     70static void inet_link_local_node_ip(addr48_t mac_addr,
     71    addr128_t ip_addr)
     72{
     73        memcpy(ip_addr, link_local_node_ip, 16);
     74       
     75        ip_addr[8] = mac_addr[0] ^ 0x02;
     76        ip_addr[9] = mac_addr[1];
     77        ip_addr[10] = mac_addr[2];
     78        ip_addr[13] = mac_addr[3];
     79        ip_addr[14] = mac_addr[4];
     80        ip_addr[15] = mac_addr[5];
     81}
     82
     83static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, uint16_t af)
     84{
     85        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
     86       
     87        int rc;
    6388        inet_packet_t packet;
    64         int rc;
    65 
    66         log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
    67         rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
     89       
     90        switch (af) {
     91        case AF_INET:
     92                rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
     93                break;
     94        case AF_INET6:
     95                rc = inet_pdu_decode6(sdu->data, sdu->size, &packet);
     96                break;
     97        default:
     98                log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid address family");
     99                return EINVAL;
     100        }
     101       
    68102        if (rc != EOK) {
    69103                log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
    70104                return rc;
    71105        }
    72 
     106       
    73107        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
    74108        rc = inet_recv_packet(&packet);
    75109        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
    76110        free(packet.data);
    77 
     111       
    78112        return rc;
    79 }
    80 
    81 static int inet_link_check_new(void)
    82 {
    83         bool already_known;
    84         category_id_t iplink_cat;
    85         service_id_t *svcs;
    86         size_t count, i;
    87         int rc;
    88 
    89         fibril_mutex_lock(&inet_discovery_lock);
    90 
    91         rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
    92         if (rc != EOK) {
    93                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
    94                 fibril_mutex_unlock(&inet_discovery_lock);
    95                 return ENOENT;
    96         }
    97 
    98         rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
    99         if (rc != EOK) {
    100                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
    101                 fibril_mutex_unlock(&inet_discovery_lock);
    102                 return EIO;
    103         }
    104 
    105         for (i = 0; i < count; i++) {
    106                 already_known = false;
    107 
    108                 list_foreach(inet_link_list, ilink_link) {
    109                         inet_link_t *ilink = list_get_instance(ilink_link,
    110                             inet_link_t, link_list);
    111                         if (ilink->svc_id == svcs[i]) {
    112                                 already_known = true;
    113                                 break;
    114                         }
    115                 }
    116 
    117                 if (!already_known) {
    118                         log_msg(LOG_DEFAULT, LVL_DEBUG, "Found IP link '%lu'",
    119                             (unsigned long) svcs[i]);
    120                         rc = inet_link_open(svcs[i]);
    121                         if (rc != EOK)
    122                                 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open IP link.");
    123                 }
    124         }
    125 
    126         fibril_mutex_unlock(&inet_discovery_lock);
    127         return EOK;
    128113}
    129114
     
    147132        if (ilink->svc_name != NULL)
    148133                free(ilink->svc_name);
     134       
    149135        free(ilink);
    150136}
    151137
    152 static int inet_link_open(service_id_t sid)
     138int inet_link_open(service_id_t sid)
    153139{
    154140        inet_link_t *ilink;
    155         iplink_addr_t iaddr;
     141        inet_addr_t iaddr;
    156142        int rc;
    157143
     
    189175                goto error;
    190176        }
     177       
     178        /*
     179         * Get the MAC address of the link. If the link has a MAC
     180         * address, we assume that it supports NDP.
     181         */
     182        rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
     183        ilink->mac_valid = (rc == EOK);
    191184
    192185        log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
    193         list_append(&ilink->link_list, &inet_link_list);
    194 
    195         inet_addrobj_t *addr;
    196 
    197         static int first = 1;
    198         /* XXX For testing: set static IP address 192.168.0.4/24 */
    199         addr = inet_addrobj_new();
    200         if (first) {
    201                 addr->naddr.ipv4 = (127 << 24) + (0 << 16) + (0 << 8) + 1;
    202                 first = 0;
    203         } else {
    204                 addr->naddr.ipv4 = (192 << 24) + (168 << 16) + (0 << 8) + 4;
    205         }
    206         addr->naddr.bits = 24;
    207         addr->ilink = ilink;
    208         addr->name = str_dup("v4a");
    209         rc = inet_addrobj_add(addr);
    210         if (rc != EOK) {
    211                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
    212                 inet_addrobj_delete(addr);
    213                 /* XXX Roll back */
    214                 return rc;
    215         }
    216 
    217         iaddr.ipv4 = addr->naddr.ipv4;
    218         rc = iplink_addr_add(ilink->iplink, &iaddr);
    219         if (rc != EOK) {
    220                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
    221                 inet_addrobj_remove(addr);
    222                 inet_addrobj_delete(addr);
    223                 /* XXX Roll back */
    224                 return rc;
    225         }
    226 
     186
     187        fibril_mutex_lock(&inet_links_lock);
     188
     189        if (inet_link_get_by_id_locked(sid) != NULL) {
     190                fibril_mutex_unlock(&inet_links_lock);
     191                log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
     192                    sid);
     193                rc = EEXIST;
     194                goto error;
     195        }
     196
     197        list_append(&ilink->link_list, &inet_links);
     198        fibril_mutex_unlock(&inet_links_lock);
     199
     200        inet_addrobj_t *addr = NULL;
     201       
     202        /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
     203        if (first_link) {
     204                addr = inet_addrobj_new();
     205               
     206                inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
     207                first_link = false;
     208        }
     209       
     210        if (addr != NULL) {
     211                addr->ilink = ilink;
     212                addr->name = str_dup("v4a");
     213               
     214                rc = inet_addrobj_add(addr);
     215                if (rc == EOK) {
     216                        inet_naddr_addr(&addr->naddr, &iaddr);
     217                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     218                        if (rc != EOK) {
     219                                log_msg(LOG_DEFAULT, LVL_ERROR,
     220                                    "Failed setting IPv4 address on internet link.");
     221                                inet_addrobj_remove(addr);
     222                                inet_addrobj_delete(addr);
     223                        }
     224                } else {
     225                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
     226                        inet_addrobj_delete(addr);
     227                }
     228        }
     229       
     230        inet_addrobj_t *addr6 = NULL;
     231       
     232        if (first_link6) {
     233                addr6 = inet_addrobj_new();
     234               
     235                inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
     236                first_link6 = false;
     237        } else if (ilink->mac_valid) {
     238                addr6 = inet_addrobj_new();
     239               
     240                addr128_t link_local;
     241                inet_link_local_node_ip(ilink->mac, link_local);
     242               
     243                inet_naddr_set6(link_local, 64, &addr6->naddr);
     244        }
     245       
     246        if (addr6 != NULL) {
     247                addr6->ilink = ilink;
     248                addr6->name = str_dup("v6a");
     249               
     250                rc = inet_addrobj_add(addr6);
     251                if (rc == EOK) {
     252                        inet_naddr_addr(&addr6->naddr, &iaddr);
     253                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     254                        if (rc != EOK) {
     255                                log_msg(LOG_DEFAULT, LVL_ERROR,
     256                                    "Failed setting IPv6 address on internet link.");
     257                                inet_addrobj_remove(addr6);
     258                                inet_addrobj_delete(addr6);
     259                        }
     260                } else {
     261                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
     262                        inet_addrobj_delete(addr6);
     263                }
     264        }
     265       
     266        log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
    227267        return EOK;
    228 
     268       
    229269error:
    230270        if (ilink->iplink != NULL)
    231271                iplink_close(ilink->iplink);
     272       
    232273        inet_link_delete(ilink);
    233274        return rc;
    234275}
    235276
    236 static void inet_link_cat_change_cb(void)
    237 {
    238         (void) inet_link_check_new();
    239 }
    240 
    241 int inet_link_discovery_start(void)
    242 {
    243         int rc;
    244 
    245         rc = loc_register_cat_change_cb(inet_link_cat_change_cb);
    246         if (rc != EOK) {
    247                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
    248                     "discovery (%d).", rc);
    249                 return rc;
    250         }
    251 
    252         return inet_link_check_new();
    253 }
    254 
    255 /** Send datagram over Internet link */
    256 int inet_link_send_dgram(inet_link_t *ilink, inet_addr_t *lsrc,
    257     inet_addr_t *ldest, inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
    258 {
    259         iplink_sdu_t sdu;
    260         inet_packet_t packet;
    261         int rc;
    262         size_t offs, roffs;
    263 
     277/** Send IPv4 datagram over Internet link
     278 *
     279 * @param ilink Internet link
     280 * @param lsrc  Source IPv4 address
     281 * @param ldest Destination IPv4 address
     282 * @param dgram IPv4 datagram body
     283 * @param proto Protocol
     284 * @param ttl   Time-to-live
     285 * @param df    Do-not-Fragment flag
     286 *
     287 * @return EOK on success
     288 * @return ENOMEM when not enough memory to create the datagram
     289 * @return ENOTSUP if networking mode is not supported
     290 *
     291 */
     292int inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
     293    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     294{
     295        addr32_t src_v4;
     296        uint16_t src_af = inet_addr_get(&dgram->src, &src_v4, NULL);
     297        if (src_af != AF_INET)
     298                return EINVAL;
     299       
     300        addr32_t dest_v4;
     301        uint16_t dest_af = inet_addr_get(&dgram->dest, &dest_v4, NULL);
     302        if (dest_af != AF_INET)
     303                return EINVAL;
     304       
    264305        /*
    265306         * Fill packet structure. Fragmentation is performed by
    266307         * inet_pdu_encode().
    267308         */
     309       
     310        iplink_sdu_t sdu;
     311       
     312        sdu.src = lsrc;
     313        sdu.dest = ldest;
     314       
     315        inet_packet_t packet;
     316       
    268317        packet.src = dgram->src;
    269318        packet.dest = dgram->dest;
     
    271320        packet.proto = proto;
    272321        packet.ttl = ttl;
     322       
     323        /* Allocate identifier */
     324        fibril_mutex_lock(&ip_ident_lock);
     325        packet.ident = ++ip_ident;
     326        fibril_mutex_unlock(&ip_ident_lock);
     327       
    273328        packet.df = df;
    274329        packet.data = dgram->data;
    275330        packet.size = dgram->size;
    276 
    277         sdu.lsrc.ipv4 = lsrc->ipv4;
    278         sdu.ldest.ipv4 = ldest->ipv4;
    279 
    280         offs = 0;
     331       
     332        int rc;
     333        size_t offs = 0;
     334       
    281335        do {
    282336                /* Encode one fragment */
    283                 rc = inet_pdu_encode(&packet, offs, ilink->def_mtu, &sdu.data,
    284                     &sdu.size, &roffs);
     337               
     338                size_t roffs;
     339                rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
     340                    &sdu.data, &sdu.size, &roffs);
    285341                if (rc != EOK)
    286342                        return rc;
    287 
     343               
    288344                /* Send the PDU */
    289345                rc = iplink_send(ilink->iplink, &sdu);
     346               
    290347                free(sdu.data);
    291 
    292348                offs = roffs;
    293349        } while (offs < packet.size);
    294 
     350       
    295351        return rc;
    296352}
    297353
     354/** Send IPv6 datagram over Internet link
     355 *
     356 * @param ilink Internet link
     357 * @param ldest Destination MAC address
     358 * @param dgram IPv6 datagram body
     359 * @param proto Next header
     360 * @param ttl   Hop limit
     361 * @param df    Do-not-Fragment flag (unused)
     362 *
     363 * @return EOK on success
     364 * @return ENOMEM when not enough memory to create the datagram
     365 *
     366 */
     367int inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
     368    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     369{
     370        addr128_t src_v6;
     371        uint16_t src_af = inet_addr_get(&dgram->src, NULL, &src_v6);
     372        if (src_af != AF_INET6)
     373                return EINVAL;
     374       
     375        addr128_t dest_v6;
     376        uint16_t dest_af = inet_addr_get(&dgram->dest, NULL, &dest_v6);
     377        if (dest_af != AF_INET6)
     378                return EINVAL;
     379       
     380        iplink_sdu6_t sdu6;
     381        addr48(ldest, sdu6.dest);
     382       
     383        /*
     384         * Fill packet structure. Fragmentation is performed by
     385         * inet_pdu_encode6().
     386         */
     387       
     388        inet_packet_t packet;
     389       
     390        packet.src = dgram->src;
     391        packet.dest = dgram->dest;
     392        packet.tos = dgram->tos;
     393        packet.proto = proto;
     394        packet.ttl = ttl;
     395       
     396        /* Allocate identifier */
     397        fibril_mutex_lock(&ip_ident_lock);
     398        packet.ident = ++ip_ident;
     399        fibril_mutex_unlock(&ip_ident_lock);
     400       
     401        packet.df = df;
     402        packet.data = dgram->data;
     403        packet.size = dgram->size;
     404       
     405        int rc;
     406        size_t offs = 0;
     407       
     408        do {
     409                /* Encode one fragment */
     410               
     411                size_t roffs;
     412                rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
     413                    &sdu6.data, &sdu6.size, &roffs);
     414                if (rc != EOK)
     415                        return rc;
     416               
     417                /* Send the PDU */
     418                rc = iplink_send6(ilink->iplink, &sdu6);
     419               
     420                free(sdu6.data);
     421                offs = roffs;
     422        } while (offs < packet.size);
     423       
     424        return rc;
     425}
     426
     427static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
     428{
     429        assert(fibril_mutex_is_locked(&inet_links_lock));
     430
     431        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     432                if (ilink->svc_id == link_id)
     433                        return ilink;
     434        }
     435
     436        return NULL;
     437}
     438
    298439inet_link_t *inet_link_get_by_id(sysarg_t link_id)
    299440{
    300         fibril_mutex_lock(&inet_discovery_lock);
    301 
    302         list_foreach(inet_link_list, elem) {
    303                 inet_link_t *ilink = list_get_instance(elem, inet_link_t,
    304                     link_list);
    305 
    306                 if (ilink->svc_id == link_id) {
    307                         fibril_mutex_unlock(&inet_discovery_lock);
    308                         return ilink;
    309                 }
    310         }
    311 
    312         fibril_mutex_unlock(&inet_discovery_lock);
    313         return NULL;
     441        inet_link_t *ilink;
     442
     443        fibril_mutex_lock(&inet_links_lock);
     444        ilink = inet_link_get_by_id_locked(link_id);
     445        fibril_mutex_unlock(&inet_links_lock);
     446
     447        return ilink;
     448}
     449
     450/** Get IDs of all links. */
     451int inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
     452{
     453        sysarg_t *id_list;
     454        size_t count, i;
     455
     456        fibril_mutex_lock(&inet_links_lock);
     457        count = list_count(&inet_links);
     458
     459        id_list = calloc(count, sizeof(sysarg_t));
     460        if (id_list == NULL) {
     461                fibril_mutex_unlock(&inet_links_lock);
     462                return ENOMEM;
     463        }
     464
     465        i = 0;
     466        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     467                id_list[i++] = ilink->svc_id;
     468                log_msg(LOG_DEFAULT, LVL_NOTE, "add link to list");
     469        }
     470
     471        fibril_mutex_unlock(&inet_links_lock);
     472
     473        log_msg(LOG_DEFAULT, LVL_NOTE, "return %zu links", count);
     474        *rid_list = id_list;
     475        *rcount = count;
     476
     477        return EOK;
    314478}
    315479
Note: See TracChangeset for help on using the changeset viewer.