From 11104933cadd49b7618d30d451aa0e00508af4ff Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 16 Aug 2010 21:45:52 +0200 Subject: [PATCH] Split DHCP code off into a separate source code file --- Makefile | 2 +- dhcp.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 86 ++------------------------------------- relayd.h | 22 +++------- 4 files changed, 132 insertions(+), 100 deletions(-) create mode 100644 dhcp.c diff --git a/Makefile b/Makefile index 1715881..5fd54e8 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LDFLAGS = 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 diff --git a/dhcp.c b/dhcp.c new file mode 100644 index 0000000..a144346 --- /dev/null +++ b/dhcp.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2010 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include + +#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; +} + + diff --git a/main.c b/main.c index 975e1ff..62d7c2b 100644 --- a/main.c +++ b/main.c @@ -329,7 +329,7 @@ static void recv_packet(struct uloop_fd *fd, unsigned int events) } 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; @@ -344,86 +344,6 @@ static void forward_bcast_packet(struct relayd_interface *from_rif, void *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); @@ -448,11 +368,11 @@ static void recv_bcast_packet(struct uloop_fd *fd, unsigned int events) 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); } diff --git a/relayd.h b/relayd.h index c8b023c..3ae4edc 100644 --- a/relayd.h +++ b/relayd.h @@ -85,21 +85,6 @@ struct arp_packet { 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; @@ -127,6 +112,11 @@ void relayd_del_interface_routes(struct relayd_interface *rif); 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 -- 2.30.2