Ignore:
File:
1 edited

Legend:

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

    r4a5a18be r417a2ba1  
    4343#include <stdlib.h>
    4444#include <str.h>
    45 
    4645#include "addrobj.h"
    4746#include "inetsrv.h"
     
    4948#include "pdu.h"
    5049
    51 static int inet_link_open(service_id_t sid);
    52 static int inet_iplink_recv(iplink_t *ilink, iplink_sdu_t *sdu);
     50static bool first_link = true;
     51static bool first_link6 = true;
     52
     53static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
     54static uint16_t ip_ident = 0;
     55
     56static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
     57static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
    5358
    5459static iplink_ev_ops_t inet_iplink_ev_ops = {
     
    5661};
    5762
    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 {
     63static LIST_INITIALIZE(inet_links);
     64static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
     65
     66static addr128_t link_local_node_ip =
     67    {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0};
     68
     69static void inet_link_local_node_ip(addr48_t mac_addr,
     70    addr128_t ip_addr)
     71{
     72        memcpy(ip_addr, link_local_node_ip, 16);
     73       
     74        ip_addr[8] = mac_addr[0] ^ 0x02;
     75        ip_addr[9] = mac_addr[1];
     76        ip_addr[10] = mac_addr[2];
     77        ip_addr[13] = mac_addr[3];
     78        ip_addr[14] = mac_addr[4];
     79        ip_addr[15] = mac_addr[5];
     80}
     81
     82static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
     83{
     84        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
     85       
     86        int rc;
    6387        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);
     88       
     89        switch (ver) {
     90        case ip_v4:
     91                rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
     92                break;
     93        case ip_v6:
     94                rc = inet_pdu_decode6(sdu->data, sdu->size, &packet);
     95                break;
     96        default:
     97                log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
     98                return EINVAL;
     99        }
     100       
    68101        if (rc != EOK) {
    69102                log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
    70103                return rc;
    71104        }
    72 
     105       
    73106        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
    74107        rc = inet_recv_packet(&packet);
    75108        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
    76109        free(packet.data);
    77 
     110       
    78111        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;
    128112}
    129113
     
    147131        if (ilink->svc_name != NULL)
    148132                free(ilink->svc_name);
     133       
    149134        free(ilink);
    150135}
    151136
    152 static int inet_link_open(service_id_t sid)
     137int inet_link_open(service_id_t sid)
    153138{
    154139        inet_link_t *ilink;
    155         iplink_addr_t iaddr;
     140        inet_addr_t iaddr;
    156141        int rc;
    157142
     
    189174                goto error;
    190175        }
     176       
     177        /*
     178         * Get the MAC address of the link. If the link has a MAC
     179         * address, we assume that it supports NDP.
     180         */
     181        rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
     182        ilink->mac_valid = (rc == EOK);
    191183
    192184        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 10.0.2.15/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 = (10 << 24) + (0 << 16) + (2 << 8) + 15;
    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 
     185
     186        fibril_mutex_lock(&inet_links_lock);
     187
     188        if (inet_link_get_by_id_locked(sid) != NULL) {
     189                fibril_mutex_unlock(&inet_links_lock);
     190                log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
     191                    sid);
     192                rc = EEXIST;
     193                goto error;
     194        }
     195
     196        list_append(&ilink->link_list, &inet_links);
     197        fibril_mutex_unlock(&inet_links_lock);
     198
     199        inet_addrobj_t *addr = NULL;
     200       
     201        /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
     202        if (first_link) {
     203                addr = inet_addrobj_new();
     204               
     205                inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
     206                first_link = false;
     207        }
     208       
     209        if (addr != NULL) {
     210                addr->ilink = ilink;
     211                addr->name = str_dup("v4a");
     212               
     213                rc = inet_addrobj_add(addr);
     214                if (rc == EOK) {
     215                        inet_naddr_addr(&addr->naddr, &iaddr);
     216                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     217                        if (rc != EOK) {
     218                                log_msg(LOG_DEFAULT, LVL_ERROR,
     219                                    "Failed setting IPv4 address on internet link.");
     220                                inet_addrobj_remove(addr);
     221                                inet_addrobj_delete(addr);
     222                        }
     223                } else {
     224                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
     225                        inet_addrobj_delete(addr);
     226                }
     227        }
     228       
     229        inet_addrobj_t *addr6 = NULL;
     230       
     231        if (first_link6) {
     232                addr6 = inet_addrobj_new();
     233               
     234                inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
     235                first_link6 = false;
     236        } else if (ilink->mac_valid) {
     237                addr6 = inet_addrobj_new();
     238               
     239                addr128_t link_local;
     240                inet_link_local_node_ip(ilink->mac, link_local);
     241               
     242                inet_naddr_set6(link_local, 64, &addr6->naddr);
     243        }
     244       
     245        if (addr6 != NULL) {
     246                addr6->ilink = ilink;
     247                addr6->name = str_dup("v6a");
     248               
     249                rc = inet_addrobj_add(addr6);
     250                if (rc == EOK) {
     251                        inet_naddr_addr(&addr6->naddr, &iaddr);
     252                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     253                        if (rc != EOK) {
     254                                log_msg(LOG_DEFAULT, LVL_ERROR,
     255                                    "Failed setting IPv6 address on internet link.");
     256                                inet_addrobj_remove(addr6);
     257                                inet_addrobj_delete(addr6);
     258                        }
     259                } else {
     260                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
     261                        inet_addrobj_delete(addr6);
     262                }
     263        }
     264       
     265        log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
    227266        return EOK;
    228 
     267       
    229268error:
    230269        if (ilink->iplink != NULL)
    231270                iplink_close(ilink->iplink);
     271       
    232272        inet_link_delete(ilink);
    233273        return rc;
    234274}
    235275
    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 
     276/** Send IPv4 datagram over Internet link
     277 *
     278 * @param ilink Internet link
     279 * @param lsrc  Source IPv4 address
     280 * @param ldest Destination IPv4 address
     281 * @param dgram IPv4 datagram body
     282 * @param proto Protocol
     283 * @param ttl   Time-to-live
     284 * @param df    Do-not-Fragment flag
     285 *
     286 * @return EOK on success
     287 * @return ENOMEM when not enough memory to create the datagram
     288 * @return ENOTSUP if networking mode is not supported
     289 *
     290 */
     291int inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
     292    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     293{
     294        addr32_t src_v4;
     295        ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
     296        if (src_ver != ip_v4)
     297                return EINVAL;
     298       
     299        addr32_t dest_v4;
     300        ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
     301        if (dest_ver != ip_v4)
     302                return EINVAL;
     303       
    264304        /*
    265305         * Fill packet structure. Fragmentation is performed by
    266306         * inet_pdu_encode().
    267307         */
     308       
     309        iplink_sdu_t sdu;
     310       
     311        sdu.src = lsrc;
     312        sdu.dest = ldest;
     313       
     314        inet_packet_t packet;
     315       
    268316        packet.src = dgram->src;
    269317        packet.dest = dgram->dest;
     
    271319        packet.proto = proto;
    272320        packet.ttl = ttl;
     321       
     322        /* Allocate identifier */
     323        fibril_mutex_lock(&ip_ident_lock);
     324        packet.ident = ++ip_ident;
     325        fibril_mutex_unlock(&ip_ident_lock);
     326       
    273327        packet.df = df;
    274328        packet.data = dgram->data;
    275329        packet.size = dgram->size;
    276 
    277         sdu.lsrc.ipv4 = lsrc->ipv4;
    278         sdu.ldest.ipv4 = ldest->ipv4;
    279 
    280         offs = 0;
     330       
     331        int rc;
     332        size_t offs = 0;
     333       
    281334        do {
    282335                /* Encode one fragment */
    283                 rc = inet_pdu_encode(&packet, offs, ilink->def_mtu, &sdu.data,
    284                     &sdu.size, &roffs);
     336               
     337                size_t roffs;
     338                rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
     339                    &sdu.data, &sdu.size, &roffs);
    285340                if (rc != EOK)
    286341                        return rc;
    287 
     342               
    288343                /* Send the PDU */
    289344                rc = iplink_send(ilink->iplink, &sdu);
     345               
    290346                free(sdu.data);
    291 
    292347                offs = roffs;
    293348        } while (offs < packet.size);
    294 
     349       
    295350        return rc;
    296351}
    297352
     353/** Send IPv6 datagram over Internet link
     354 *
     355 * @param ilink Internet link
     356 * @param ldest Destination MAC address
     357 * @param dgram IPv6 datagram body
     358 * @param proto Next header
     359 * @param ttl   Hop limit
     360 * @param df    Do-not-Fragment flag (unused)
     361 *
     362 * @return EOK on success
     363 * @return ENOMEM when not enough memory to create the datagram
     364 *
     365 */
     366int inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
     367    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     368{
     369        addr128_t src_v6;
     370        ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
     371        if (src_ver != ip_v6)
     372                return EINVAL;
     373       
     374        addr128_t dest_v6;
     375        ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
     376        if (dest_ver != ip_v6)
     377                return EINVAL;
     378       
     379        iplink_sdu6_t sdu6;
     380        addr48(ldest, sdu6.dest);
     381       
     382        /*
     383         * Fill packet structure. Fragmentation is performed by
     384         * inet_pdu_encode6().
     385         */
     386       
     387        inet_packet_t packet;
     388       
     389        packet.src = dgram->src;
     390        packet.dest = dgram->dest;
     391        packet.tos = dgram->tos;
     392        packet.proto = proto;
     393        packet.ttl = ttl;
     394       
     395        /* Allocate identifier */
     396        fibril_mutex_lock(&ip_ident_lock);
     397        packet.ident = ++ip_ident;
     398        fibril_mutex_unlock(&ip_ident_lock);
     399       
     400        packet.df = df;
     401        packet.data = dgram->data;
     402        packet.size = dgram->size;
     403       
     404        int rc;
     405        size_t offs = 0;
     406       
     407        do {
     408                /* Encode one fragment */
     409               
     410                size_t roffs;
     411                rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
     412                    &sdu6.data, &sdu6.size, &roffs);
     413                if (rc != EOK)
     414                        return rc;
     415               
     416                /* Send the PDU */
     417                rc = iplink_send6(ilink->iplink, &sdu6);
     418               
     419                free(sdu6.data);
     420                offs = roffs;
     421        } while (offs < packet.size);
     422       
     423        return rc;
     424}
     425
     426static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
     427{
     428        assert(fibril_mutex_is_locked(&inet_links_lock));
     429
     430        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     431                if (ilink->svc_id == link_id)
     432                        return ilink;
     433        }
     434
     435        return NULL;
     436}
     437
    298438inet_link_t *inet_link_get_by_id(sysarg_t link_id)
    299439{
    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;
     440        inet_link_t *ilink;
     441
     442        fibril_mutex_lock(&inet_links_lock);
     443        ilink = inet_link_get_by_id_locked(link_id);
     444        fibril_mutex_unlock(&inet_links_lock);
     445
     446        return ilink;
     447}
     448
     449/** Get IDs of all links. */
     450int inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
     451{
     452        sysarg_t *id_list;
     453        size_t count, i;
     454
     455        fibril_mutex_lock(&inet_links_lock);
     456        count = list_count(&inet_links);
     457
     458        id_list = calloc(count, sizeof(sysarg_t));
     459        if (id_list == NULL) {
     460                fibril_mutex_unlock(&inet_links_lock);
     461                return ENOMEM;
     462        }
     463
     464        i = 0;
     465        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     466                id_list[i++] = ilink->svc_id;
     467                log_msg(LOG_DEFAULT, LVL_NOTE, "add link to list");
     468        }
     469
     470        fibril_mutex_unlock(&inet_links_lock);
     471
     472        log_msg(LOG_DEFAULT, LVL_NOTE, "return %zu links", count);
     473        *rid_list = id_list;
     474        *rcount = count;
     475
     476        return EOK;
    314477}
    315478
Note: See TracChangeset for help on using the changeset viewer.