X-Git-Url: http://git.archive.openwrt.org/?p=project%2Frelayd.git;a=blobdiff_plain;f=dhcp.c;h=9dbea282b739bc11075869cafc269b26e3a2d1c1;hp=a144346dd2ab8422f981bccb1c5e697407eddf34;hb=931b54fa982bcc163009a3fe61cff5173aaa79d8;hpb=11104933cadd49b7618d30d451aa0e00508af4ff diff --git a/dhcp.c b/dhcp.c index a144346..9dbea28 100644 --- a/dhcp.c +++ b/dhcp.c @@ -29,6 +29,19 @@ struct ip_packet { struct iphdr iph; } __packed; + +enum { + DHCP_OPTION_ROUTER = 0x03, + DHCP_OPTION_ROUTES = 0x79, + DHCP_OPTION_END = 0xff, +}; + +struct dhcp_option { + uint8_t code; + uint8_t len; + uint8_t data[]; +}; + struct dhcp_header { uint8_t op, htype, hlen, hops; uint32_t xit; @@ -37,6 +50,8 @@ struct dhcp_header { unsigned char chaddr[16]; unsigned char sname[64]; unsigned char file[128]; + uint32_t cookie; + uint8_t option_data[]; } __packed; static uint16_t @@ -65,11 +80,46 @@ chksum(uint16_t sum, const uint8_t *data, uint16_t len) return sum; } +static void +parse_dhcp_options(struct relayd_host *host, struct dhcp_header *dhcp, int len) +{ + uint8_t *end = (uint8_t *) dhcp + len; + struct dhcp_option *opt = (void *)dhcp->option_data; + static const uint8_t dest[4] = { 0, 0, 0, 0 }; + + while((uint8_t *) opt < end) { + if ((uint8_t *) opt + opt->len > end) + break; + + opt = (void *) &opt->data[opt->len]; + switch(opt->code) { + case DHCP_OPTION_ROUTER: + DPRINTF(2, "Found a DHCP router option, len=%d\n", opt->len); + if (!memcmp(opt->data, host->ipaddr, 4)) + relayd_add_host_route(host, dest, 0); + else + relayd_add_pending_route(opt->data, dest, 0, 10000); + break; + case DHCP_OPTION_ROUTES: + DPRINTF(2, "Found a DHCP static routes option, len=%d\n", opt->len); + break; + case DHCP_OPTION_END: + opt = (void *) end; + continue; + default: + DPRINTF(3, "Skipping unknown DHCP option %02x\n", opt->code); + continue; + } + + } +} + bool relayd_handle_dhcp_packet(struct relayd_interface *rif, void *data, int len, bool forward) { struct ip_packet *pkt = data; struct udphdr *udp; struct dhcp_header *dhcp; + struct relayd_host *host; int udplen; uint16_t sum; @@ -98,8 +148,11 @@ bool relayd_handle_dhcp_packet(struct relayd_interface *rif, void *data, int len if (!forward) return true; - if (dhcp->op == 2) - relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr); + if (dhcp->op == 2) { + host = relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr); + if (host) + parse_dhcp_options(host, dhcp, udplen - sizeof(struct udphdr)); + } DPRINTF(2, "%s: handling DHCP %s\n", rif->ifname, (dhcp->op == 1 ? "request" : "response"));