2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License v2 as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18 #include <sys/socket.h>
28 struct ether_header eth;
34 DHCP_OPTION_ROUTER = 0x03,
35 DHCP_OPTION_ROUTES = 0x79,
36 DHCP_OPTION_END = 0xff,
46 uint8_t op, htype, hlen, hops;
49 struct in_addr ciaddr, yiaddr, siaddr, giaddr;
50 unsigned char chaddr[16];
51 unsigned char sname[64];
52 unsigned char file[128];
54 uint8_t option_data[];
58 chksum(uint16_t sum, const uint8_t *data, uint16_t len)
63 last = data + len - 1;
66 t = (data[0] << 8) + data[1];
74 t = (data[0] << 8) + 0;
84 parse_dhcp_options(struct relayd_host *host, struct dhcp_header *dhcp, int len)
86 uint8_t *end = (uint8_t *) dhcp + len;
87 struct dhcp_option *opt = (void *)dhcp->option_data;
88 static const uint8_t dest[4] = { 0, 0, 0, 0 };
90 while((uint8_t *) opt < end) {
91 if ((uint8_t *) opt + opt->len > end)
94 opt = (void *) &opt->data[opt->len];
96 case DHCP_OPTION_ROUTER:
97 DPRINTF(2, "Found a DHCP router option, len=%d\n", opt->len);
98 if (!memcmp(opt->data, host->ipaddr, 4))
99 relayd_add_host_route(host, dest, 0);
101 relayd_add_pending_route(opt->data, dest, 0, 10000);
103 case DHCP_OPTION_ROUTES:
104 DPRINTF(2, "Found a DHCP static routes option, len=%d\n", opt->len);
106 case DHCP_OPTION_END:
110 DPRINTF(3, "Skipping unknown DHCP option %02x\n", opt->code);
117 bool relayd_handle_dhcp_packet(struct relayd_interface *rif, void *data, int len, bool forward)
119 struct ip_packet *pkt = data;
121 struct dhcp_header *dhcp;
122 struct relayd_host *host;
126 if (pkt->eth.ether_type != htons(ETH_P_IP))
129 if (pkt->iph.version != 4)
132 if (pkt->iph.protocol != IPPROTO_UDP)
135 udp = (void *) ((char *) &pkt->iph + (pkt->iph.ihl << 2));
136 dhcp = (void *) (udp + 1);
138 udplen = ntohs(udp->len);
139 if (udplen > len - ((char *) udp - (char *) data))
142 if (udp->dest != htons(67) && udp->source != htons(67))
145 if (dhcp->op != 1 && dhcp->op != 2)
152 host = relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr);
154 parse_dhcp_options(host, dhcp, udplen - sizeof(struct udphdr));
157 DPRINTF(2, "%s: handling DHCP %s\n", rif->ifname, (dhcp->op == 1 ? "request" : "response"));
159 dhcp->flags |= htons(DHCP_FLAG_BROADCAST);
162 sum = udplen + IPPROTO_UDP;
163 sum = chksum(sum, (void *) &pkt->iph.saddr, 8);
164 sum = chksum(sum, (void *) udp, udplen);
168 udp->check = htons(~sum);
170 relayd_forward_bcast_packet(rif, data, len);