all: relayd
-relayd: uloop.o main.o route.o
+relayd: uloop.o main.o route.o dhcp.o
$(CC) -o $@ $^ $(LDFLAGS)
relayd.h: list.h
--- /dev/null
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "relayd.h"
+
+struct ip_packet {
+ struct ether_header eth;
+ struct iphdr iph;
+} __packed;
+
+struct dhcp_header {
+ uint8_t op, htype, hlen, hops;
+ uint32_t xit;
+ uint16_t secs, flags;
+ struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+ unsigned char chaddr[16];
+ unsigned char sname[64];
+ unsigned char file[128];
+} __packed;
+
+static uint16_t
+chksum(uint16_t sum, const uint8_t *data, uint16_t len)
+{
+ const uint8_t *last;
+ uint16_t t;
+
+ last = data + len - 1;
+
+ while(data < last) {
+ t = (data[0] << 8) + data[1];
+ sum += t;
+ if(sum < t)
+ sum++;
+ data += 2;
+ }
+
+ if(data == last) {
+ t = (data[0] << 8) + 0;
+ sum += t;
+ if(sum < t)
+ sum++;
+ }
+
+ return sum;
+}
+
+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;
+ int udplen;
+ uint16_t sum;
+
+ if (pkt->eth.ether_type != htons(ETH_P_IP))
+ return false;
+
+ if (pkt->iph.version != 4)
+ return false;
+
+ if (pkt->iph.protocol != IPPROTO_UDP)
+ return false;
+
+ udp = (void *) ((char *) &pkt->iph + (pkt->iph.ihl << 2));
+ dhcp = (void *) (udp + 1);
+
+ udplen = ntohs(udp->len);
+ if (udplen > len - ((char *) udp - (char *) data))
+ return false;
+
+ if (udp->dest != htons(67) && udp->source != htons(67))
+ return false;
+
+ if (dhcp->op != 1 && dhcp->op != 2)
+ return false;
+
+ if (!forward)
+ return true;
+
+ if (dhcp->op == 2)
+ relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr);
+
+ DPRINTF(2, "%s: handling DHCP %s\n", rif->ifname, (dhcp->op == 1 ? "request" : "response"));
+
+ dhcp->flags |= htons(DHCP_FLAG_BROADCAST);
+
+ udp->check = 0;
+ sum = udplen + IPPROTO_UDP;
+ sum = chksum(sum, (void *) &pkt->iph.saddr, 8);
+ sum = chksum(sum, (void *) udp, udplen);
+ if (sum == 0)
+ sum = 0xffff;
+
+ udp->check = htons(~sum);
+
+ relayd_forward_bcast_packet(rif, data, len);
+
+ return true;
+}
+
+
} while (1);
}
-static void forward_bcast_packet(struct relayd_interface *from_rif, void *packet, int len)
+void relayd_forward_bcast_packet(struct relayd_interface *from_rif, void *packet, int len)
{
struct relayd_interface *rif;
struct ether_header *eth = packet;
}
}
-static uint16_t
-chksum(uint16_t sum, const uint8_t *data, uint16_t len)
-{
- const uint8_t *last;
- uint16_t t;
-
- last = data + len - 1;
-
- while(data < last) {
- t = (data[0] << 8) + data[1];
- sum += t;
- if(sum < t)
- sum++;
- data += 2;
- }
-
- if(data == last) {
- t = (data[0] << 8) + 0;
- sum += t;
- if(sum < t)
- sum++;
- }
-
- return sum;
-}
-
-static bool forward_dhcp_packet(struct relayd_interface *rif, void *data, int len)
-{
- struct ip_packet *pkt = data;
- struct udphdr *udp;
- struct dhcp_header *dhcp;
- int udplen;
- uint16_t sum;
-
- if (pkt->eth.ether_type != htons(ETH_P_IP))
- return false;
-
- if (pkt->iph.version != 4)
- return false;
-
- if (pkt->iph.protocol != IPPROTO_UDP)
- return false;
-
- udp = (void *) ((char *) &pkt->iph + (pkt->iph.ihl << 2));
- dhcp = (void *) (udp + 1);
-
- udplen = ntohs(udp->len);
- if (udplen > len - ((char *) udp - (char *) data))
- return false;
-
- if (udp->dest != htons(67) && udp->source != htons(67))
- return false;
-
- if (dhcp->op != 1 && dhcp->op != 2)
- return false;
-
- if (!forward_dhcp)
- return true;
-
- if (dhcp->op == 2)
- relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr);
-
- DPRINTF(2, "%s: handling DHCP %s\n", rif->ifname, (dhcp->op == 1 ? "request" : "response"));
-
- dhcp->flags |= htons(DHCP_FLAG_BROADCAST);
-
- udp->check = 0;
- sum = udplen + IPPROTO_UDP;
- sum = chksum(sum, (void *) &pkt->iph.saddr, 8);
- sum = chksum(sum, (void *) udp, udplen);
- if (sum == 0)
- sum = 0xffff;
-
- udp->check = htons(~sum);
-
- forward_bcast_packet(rif, data, len);
-
- return true;
-}
-
static void recv_bcast_packet(struct uloop_fd *fd, unsigned int events)
{
struct relayd_interface *rif = container_of(fd, struct relayd_interface, bcast_fd);
if (!forward_bcast && !forward_dhcp)
continue;
- if (forward_dhcp_packet(rif, pktbuf, pktlen))
+ if (relayd_handle_dhcp_packet(rif, pktbuf, pktlen, forward_dhcp))
continue;
if (forward_bcast)
- forward_bcast_packet(rif, pktbuf, pktlen);
+ relayd_forward_bcast_packet(rif, pktbuf, pktlen);
} while (1);
}
struct ether_arp arp;
} __packed;
-struct ip_packet {
- struct ether_header eth;
- struct iphdr iph;
-} __packed;
-
-struct dhcp_header {
- uint8_t op, htype, hlen, hops;
- uint32_t xit;
- uint16_t secs, flags;
- struct in_addr ciaddr, yiaddr, siaddr, giaddr;
- unsigned char chaddr[16];
- unsigned char sname[64];
- unsigned char file[128];
-} __packed;
-
struct rtnl_req {
struct nlmsghdr nl;
struct rtmsg rt;
int relayd_rtnl_init(void);
void relayd_rtnl_done(void);
-struct relayd_host *relayd_refresh_host(struct relayd_interface *rif, const uint8_t *lladdr, const uint8_t *ipaddr);
+struct relayd_host *relayd_refresh_host(struct relayd_interface *rif,
+ const uint8_t *lladdr,
+ const uint8_t *ipaddr);
+
+void relayd_forward_bcast_packet(struct relayd_interface *from_rif, void *packet, int len);
+bool relayd_handle_dhcp_packet(struct relayd_interface *rif, void *data, int len, bool forward);
#endif