Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/dhcp/dhcp.c

    r947e2ef r5a324d99  
    3535 */
    3636
     37#include <adt/list.h>
    3738#include <bitops.h>
     39#include <errno.h>
     40#include <fibril_synch.h>
    3841#include <inet/addr.h>
    3942#include <inet/dnsr.h>
    4043#include <inet/inetcfg.h>
     44#include <io/log.h>
    4145#include <loc.h>
    42 #include <net/in.h>
    43 #include <net/inet.h>
    44 #include <net/socket.h>
    4546#include <stdio.h>
    4647#include <stdlib.h>
    4748
     49#include "dhcp.h"
    4850#include "dhcp_std.h"
    49 
    50 #define NAME "dhcp"
     51#include "transport.h"
     52
     53enum {
     54        /** In microseconds */
     55        dhcp_discover_timeout_val = 5 * 1000 * 1000,
     56        /** In microseconds */
     57        dhcp_request_timeout_val = 1 * 1000 * 1000,
     58        dhcp_discover_retries = 5,
     59        dhcp_request_retries = 3
     60};
    5161
    5262#define MAX_MSG_SIZE 1024
    53 
    54 static int transport_fd = -1;
    55 static inet_link_info_t link_info;
    5663static uint8_t msgbuf[MAX_MSG_SIZE];
     64
     65/** List of registered links (of dhcp_link_t) */
     66static list_t dhcp_links;
     67
     68static void dhcpsrv_discover_timeout(void *);
     69static void dhcpsrv_request_timeout(void *);
     70
     71typedef enum {
     72        ds_bound,
     73        ds_fail,
     74        ds_init,
     75        ds_init_reboot,
     76        ds_rebinding,
     77        ds_renewing,
     78        ds_requesting,
     79        ds_selecting
     80} dhcp_state_t;
    5781
    5882typedef struct {
     
    6993} dhcp_offer_t;
    7094
     95typedef struct {
     96        /** Link to dhcp_links list */
     97        link_t links;
     98        /** Link service ID */
     99        service_id_t link_id;
     100        /** Link info */
     101        inet_link_info_t link_info;
     102        /** Transport */
     103        dhcp_transport_t dt;
     104        /** Transport timeout */
     105        fibril_timer_t *timeout;
     106        /** Number of retries */
     107        int retries_left;
     108        /** Link state */
     109        dhcp_state_t state;
     110        /** Last received offer */
     111        dhcp_offer_t offer;
     112} dhcp_link_t;
     113
     114static void dhcpsrv_recv(void *, void *, size_t);
     115
    71116/** Decode subnet mask into subnet prefix length. */
    72117static int subnet_mask_decode(uint32_t mask, int *bits)
     
    101146}
    102147
    103 static int dhcp_send(void *msg, size_t size)
    104 {
    105         struct sockaddr_in addr;
    106         int rc;
    107 
    108         addr.sin_family = AF_INET;
    109         addr.sin_port = htons(dhcp_server_port);
    110         addr.sin_addr.s_addr = htonl(addr32_broadcast_all_hosts);
    111 
    112         rc = sendto(transport_fd, msg, size, 0,
    113             (struct sockaddr *)&addr, sizeof(addr));
    114         if (rc != EOK) {
    115                 printf("Sending failed\n");
    116                 return rc;
    117         }
    118 
    119         return EOK;
    120 }
    121 
    122 static int dhcp_send_discover(void)
     148static int dhcp_send_discover(dhcp_link_t *dlink)
    123149{
    124150        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    132158        hdr->flags = flag_broadcast;
    133159
    134         addr48(link_info.mac_addr, hdr->chaddr);
     160        addr48(dlink->link_info.mac_addr, hdr->chaddr);
    135161        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    136162
     
    140166        opt[3] = opt_end;
    141167
    142         return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + 4);
    143 }
    144 
    145 static int dhcp_recv_msg(void **rmsg, size_t *rsize)
    146 {
    147         struct sockaddr_in src_addr;
    148         socklen_t src_addr_size;
    149         size_t recv_size;
    150         int rc;
    151 
    152         src_addr_size = sizeof(src_addr);
    153         rc = recvfrom(transport_fd, msgbuf, MAX_MSG_SIZE, 0,
    154             (struct sockaddr *)&src_addr, &src_addr_size);
    155         if (rc < 0) {
    156                 printf("recvfrom failed (%d)\n", rc);
    157                 return rc;
    158         }
    159 
    160         recv_size = (size_t)rc;
    161         *rmsg = msgbuf;
    162         *rsize = recv_size;
    163 
    164         return EOK;
    165 }
    166 
    167 static int dhcp_send_request(dhcp_offer_t *offer)
     168        return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + 4);
     169}
     170
     171static int dhcp_send_request(dhcp_link_t *dlink, dhcp_offer_t *offer)
    168172{
    169173        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    178182        hdr->flags = flag_broadcast;
    179183        hdr->ciaddr = host2uint32_t_be(offer->oaddr.addr);
    180         addr48(link_info.mac_addr, hdr->chaddr);
     184        addr48(dlink->link_info.mac_addr, hdr->chaddr);
    181185        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    182186
     
    203207        opt[i++] = opt_end;
    204208
    205         return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + i);
    206 }
    207 
    208 static int dhcp_recv_reply(void *msg, size_t size, dhcp_offer_t *offer)
     209        return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
     210}
     211
     212static int dhcp_parse_reply(void *msg, size_t size, dhcp_offer_t *offer)
    209213{
    210214        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg;
     
    222226        size_t i;
    223227
    224         printf("Receive reply\n");
     228        log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply");
    225229        memset(offer, 0, sizeof(*offer));
    226230
    227         yiaddr.family = AF_INET;
    228         yiaddr.addr = uint32_t_be2host(hdr->yiaddr);
     231        inet_addr_set(uint32_t_be2host(hdr->yiaddr), &yiaddr);
    229232        rc = inet_addr_format(&yiaddr, &saddr);
    230233        if (rc != EOK)
    231234                return rc;
    232235
    233         printf("Your IP address: %s\n", saddr);
     236        log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr);
    234237        free(saddr);
    235238
    236         siaddr.family = AF_INET;
    237         siaddr.addr = uint32_t_be2host(hdr->siaddr);
     239        inet_addr_set(uint32_t_be2host(hdr->siaddr), &siaddr);
    238240        rc = inet_addr_format(&siaddr, &saddr);
    239241        if (rc != EOK)
    240242                return rc;
    241243
    242         printf("Next server IP address: %s\n", saddr);
     244        log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr);
    243245        free(saddr);
    244246
    245         giaddr.family = AF_INET;
    246         giaddr.addr = uint32_t_be2host(hdr->giaddr);
     247        inet_addr_set(uint32_t_be2host(hdr->giaddr), &giaddr);
    247248        rc = inet_addr_format(&giaddr, &saddr);
    248249        if (rc != EOK)
    249250                return rc;
    250251
    251         printf("Relay agent IP address: %s\n", saddr);
     252        log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr);
    252253        free(saddr);
    253254
    254         offer->oaddr.family = AF_INET;
    255         offer->oaddr.addr = yiaddr.addr;
     255        inet_naddr_set(yiaddr.addr, 0, &offer->oaddr);
    256256
    257257        msgb = (uint8_t *)msg;
     
    293293                        if (opt_len != 4)
    294294                                return EINVAL;
    295                         offer->srv_addr.family = AF_INET;
    296                         offer->srv_addr.addr = dhcp_uint32_decode(&msgb[i]);
     295                        inet_addr_set(dhcp_uint32_decode(&msgb[i]),
     296                            &offer->srv_addr);
    297297                        have_server_id = true;
    298298                        break;
     
    300300                        if (opt_len != 4)
    301301                                return EINVAL;
    302                         offer->router.family = AF_INET;
    303                         offer->router.addr = dhcp_uint32_decode(&msgb[i]);
     302                        inet_addr_set(dhcp_uint32_decode(&msgb[i]),
     303                            &offer->router);
    304304                        break;
    305305                case opt_dns_server:
    306306                        if (opt_len != 4)
    307307                                return EINVAL;
    308                         offer->dns_server.family = AF_INET;
    309                         offer->dns_server.addr = dhcp_uint32_decode(&msgb[i]);
     308                        inet_addr_set(dhcp_uint32_decode(&msgb[i]),
     309                            &offer->dns_server);
    310310                        break;
    311311                case opt_end:
     
    320320
    321321        if (!have_server_id) {
    322                 printf("Missing server ID option.\n");
     322                log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option.");
    323323                return rc;
    324324        }
    325325
    326326        if (!have_subnet_mask) {
    327                 printf("Missing subnet mask option.\n");
     327                log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option.");
    328328                return rc;
    329329        }
     
    333333                return rc;
    334334
    335         printf("Offered network address: %s\n", saddr);
     335        log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr);
    336336        free(saddr);
    337337
     
    341341                        return rc;
    342342
    343                 printf("Router address: %s\n", saddr);
     343                log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr);
    344344                free(saddr);
    345345        }
     
    350350                        return rc;
    351351
    352                 printf("DNS server: %s\n", saddr);
     352                log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr);
    353353                free(saddr);
    354354        }
     
    367367            &addr_id);
    368368        if (rc != EOK) {
    369                 printf("Error creating IP address %s (%d)\n", "dhcp4a", rc);
     369                log_msg(LOG_DEFAULT, LVL_ERROR,
     370                    "Error creating IP address %s (%d)", "dhcp4a", rc);
    370371                return rc;
    371372        }
    372373
    373374        if (offer->router.addr != 0) {
    374                 defr.family = AF_INET;
    375                 defr.addr = 0;
    376                 defr.prefix = 0;
     375                inet_naddr_set(0, 0, &defr);
    377376
    378377                rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id);
    379378                if (rc != EOK) {
    380                         printf("Error creating default route %s (%d).\n", "dhcpdef",
    381                             rc);
     379                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating "
     380                            "default route %s (%d).", "dhcpdef", rc);
    382381                        return rc;
    383382                }
     
    387386                rc = dnsr_set_srvaddr(&offer->dns_server);
    388387                if (rc != EOK) {
    389                         printf("%s: Error setting nameserver address (%d))\n",
    390                             NAME, rc);
     388                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting "
     389                            "nameserver address (%d))", rc);
    391390                        return rc;
    392391                }
     
    396395}
    397396
    398 int main(int argc, char *argv[])
    399 {
    400         int fd;
    401         struct sockaddr_in laddr;
    402         void *msg;
    403         service_id_t iplink;
    404         size_t msg_size;
     397void dhcpsrv_links_init(void)
     398{
     399        list_initialize(&dhcp_links);
     400}
     401
     402static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id)
     403{
     404        list_foreach(dhcp_links, links, dhcp_link_t, dlink) {
     405                if (dlink->link_id == link_id)
     406                        return dlink;
     407        }
     408
     409        return NULL;
     410}
     411
     412static void dhcp_link_set_failed(dhcp_link_t *dlink)
     413{
     414        log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s",
     415            dlink->link_info.name);
     416        dlink->state = ds_fail;
     417}
     418
     419int dhcpsrv_link_add(service_id_t link_id)
     420{
     421        dhcp_link_t *dlink;
     422        int rc;
     423
     424        log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
     425
     426        if (dhcpsrv_link_find(link_id) != NULL) {
     427                log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
     428                    link_id);
     429                return EEXIST;
     430        }
     431
     432        dlink = calloc(1, sizeof(dhcp_link_t));
     433        if (dlink == NULL)
     434                return ENOMEM;
     435
     436        dlink->link_id = link_id;
     437        dlink->timeout = fibril_timer_create();
     438        if (dlink->timeout == NULL) {
     439                rc = ENOMEM;
     440                goto error;
     441        }
     442
     443        /* Get link hardware address */
     444        rc = inetcfg_link_get(link_id, &dlink->link_info);
     445        if (rc != EOK) {
     446                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties "
     447                    "for link %zu.", link_id);
     448                rc = EIO;
     449                goto error;
     450        }
     451
     452        rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink);
     453        if (rc != EOK) {
     454                log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP "
     455                    "transport for link %s.", dlink->link_info.name);
     456                rc = EIO;
     457                goto error;
     458        }
     459
     460        dlink->state = ds_selecting;
     461
     462        log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
     463        rc = dhcp_send_discover(dlink);
     464        if (rc != EOK) {
     465                log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER.");
     466                dhcp_link_set_failed(dlink);
     467                rc = EIO;
     468                goto error;
     469        }
     470
     471        dlink->retries_left = dhcp_discover_retries;
     472        fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
     473            dhcpsrv_discover_timeout, dlink);
     474
     475        list_append(&dlink->links, &dhcp_links);
     476
     477        return EOK;
     478error:
     479        if (dlink != NULL && dlink->timeout != NULL)
     480                fibril_timer_destroy(dlink->timeout);
     481        free(dlink);
     482        return rc;
     483}
     484
     485int dhcpsrv_link_remove(service_id_t link_id)
     486{
     487        return ENOTSUP;
     488}
     489
     490static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer)
     491{
     492        int rc;
     493
     494        if (dlink->state != ds_selecting) {
     495                log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state "
     496                    " %d, ignoring.", (int)dlink->state);
     497                return;
     498        }
     499
     500        fibril_timer_clear(dlink->timeout);
     501        dlink->offer = *offer;
     502        dlink->state = ds_requesting;
     503
     504        log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
     505        rc = dhcp_send_request(dlink, offer);
     506        if (rc != EOK) {
     507                log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
     508                return;
     509        }
     510
     511        dlink->retries_left = dhcp_request_retries;
     512        fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
     513            dhcpsrv_request_timeout, dlink);
     514}
     515
     516static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer)
     517{
     518        int rc;
     519
     520        if (dlink->state != ds_requesting) {
     521                log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state "
     522                    " %d, ignoring.", (int)dlink->state);
     523                return;
     524        }
     525
     526        fibril_timer_clear(dlink->timeout);
     527        dlink->offer = *offer;
     528        dlink->state = ds_bound;
     529
     530        rc = dhcp_cfg_create(dlink->link_id, offer);
     531        if (rc != EOK) {
     532                log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration.");
     533                return;
     534        }
     535
     536        log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.",
     537            dlink->link_info.name);
     538}
     539
     540static void dhcpsrv_recv(void *arg, void *msg, size_t size)
     541{
     542        dhcp_link_t *dlink = (dhcp_link_t *)arg;
    405543        dhcp_offer_t offer;
    406544        int rc;
    407545
    408         if (argc < 2) {
    409                 printf("syntax: %s <ip-link>\n", NAME);
    410                 return 1;
    411         }
    412 
    413         rc = inetcfg_init();
    414         if (rc != EOK) {
    415                 printf("Error contacting inet configuration service.\n");
    416                 return 1;
    417         }
    418 
    419         rc = loc_service_get_id(argv[1], &iplink, 0);
    420         if (rc != EOK) {
    421                 printf("Error resolving service '%s'.\n", argv[1]);
    422                 return 1;
    423         }
    424 
    425         /* Get link hardware address */
    426         rc = inetcfg_link_get(iplink, &link_info);
    427         if (rc != EOK) {
    428                 printf("Error getting properties for link '%s'.\n", argv[1]);
    429                 return 1;
    430         }
    431 
    432         laddr.sin_family = AF_INET;
    433         laddr.sin_port = htons(dhcp_client_port);
    434         laddr.sin_addr.s_addr = INADDR_ANY;
    435 
    436         fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    437         if (fd < 0)
    438                 return 1;
    439 
    440         printf("Bind socket.\n");
    441         rc = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
    442         if (rc != EOK)
    443                 return 1;
    444 
    445         printf("Set socket options\n");
    446         rc = setsockopt(fd, SOL_SOCKET, SO_IPLINK, &iplink, sizeof(iplink));
    447         if (rc != EOK)
    448                 return 1;
    449 
    450         transport_fd = fd;
    451 
    452         printf("Send DHCPDISCOVER\n");
    453         rc = dhcp_send_discover();
    454         if (rc != EOK)
    455                 return 1;
    456 
    457         rc = dhcp_recv_msg(&msg, &msg_size);
    458         if (rc != EOK)
    459                 return 1;
    460 
    461         printf("Received %zu bytes\n", msg_size);
    462 
    463         rc = dhcp_recv_reply(msg, msg_size, &offer);
    464         if (rc != EOK)
    465                 return 1;
    466 
    467         rc = dhcp_send_request(&offer);
    468         if (rc != EOK)
    469                 return 1;
    470 
    471         rc = dhcp_recv_msg(&msg, &msg_size);
    472         if (rc != EOK)
    473                 return 1;
    474 
    475         printf("Received %zu bytes\n", msg_size);
    476 
    477         rc = dhcp_recv_reply(msg, msg_size, &offer);
    478         if (rc != EOK)
    479                 return 1;
    480 
    481         rc = dhcp_cfg_create(iplink, &offer);
    482         if (rc != EOK)
    483                 return 1;
    484 
    485         closesocket(fd);
    486         return 0;
     546        log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes",
     547            dlink->link_info.name, size);
     548
     549        rc = dhcp_parse_reply(msg, size, &offer);
     550        if (rc != EOK) {
     551                log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply");
     552                return;
     553        }
     554
     555        switch (offer.msg_type) {
     556        case msg_dhcpoffer:
     557                dhcpsrv_recv_offer(dlink, &offer);
     558                break;
     559        case msg_dhcpack:
     560                dhcpsrv_recv_ack(dlink, &offer);
     561                break;
     562        default:
     563                log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected "
     564                    "message type. %d", (int)offer.msg_type);
     565                break;
     566        }
     567}
     568
     569static void dhcpsrv_discover_timeout(void *arg)
     570{
     571        dhcp_link_t *dlink = (dhcp_link_t *)arg;
     572        int rc;
     573
     574        assert(dlink->state == ds_selecting);
     575        log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_discover_timeout",
     576            dlink->link_info.name);
     577
     578        if (dlink->retries_left == 0) {
     579                log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
     580                dhcp_link_set_failed(dlink);
     581                return;
     582        }
     583        --dlink->retries_left;
     584
     585        log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
     586        rc = dhcp_send_discover(dlink);
     587        if (rc != EOK) {
     588                log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER");
     589                dhcp_link_set_failed(dlink);
     590                return;
     591        }
     592
     593        fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
     594            dhcpsrv_discover_timeout, dlink);
     595}
     596
     597static void dhcpsrv_request_timeout(void *arg)
     598{
     599        dhcp_link_t *dlink = (dhcp_link_t *)arg;
     600        int rc;
     601
     602        assert(dlink->state == ds_requesting);
     603        log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_request_timeout",
     604            dlink->link_info.name);
     605
     606        if (dlink->retries_left == 0) {
     607                log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
     608                dhcp_link_set_failed(dlink);
     609                return;
     610        }
     611        --dlink->retries_left;
     612
     613        log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
     614        rc = dhcp_send_request(dlink, &dlink->offer);
     615        if (rc != EOK) {
     616                log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
     617                dhcp_link_set_failed(dlink);
     618                return;
     619        }
     620
     621        fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
     622            dhcpsrv_request_timeout, dlink);
    487623}
    488624
Note: See TracChangeset for help on using the changeset viewer.