1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright 2008, The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/uio.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/socket.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/in.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/ip.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/udp.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <linux/if_packet.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <linux/if_ether.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#ifdef ANDROID
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define LOG_TAG "DHCP"
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/log.h>
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#else
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
348d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block#define ALOGD printf
35ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block#define ALOGW printf
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "dhcpmsg.h"
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint fatal();
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
42a5db95da3801cd82df80c41996b1e6f69a9acecfEdwin Vaneint open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int s, flag;
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct sockaddr_ll bindaddr;
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("socket(PF_PACKET)");
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&bindaddr, 0, sizeof(bindaddr));
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_family = AF_PACKET;
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_protocol = htons(ETH_P_IP);
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_halen = ETH_ALEN;
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_ifindex = if_index;
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("Cannot bind raw socket to interface");
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return s;
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t *up = (uint16_t *)buffer;
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t sum = startsum;
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t upper16;
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (count > 1) {
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum += *up++;
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        count -= 2;
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (count > 0) {
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum += (uint16_t) *(uint8_t *)up;
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while ((upper16 = (sum >> 16)) != 0) {
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum = (sum & 0xffff) + upper16;
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return sum;
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic uint32_t finish_sum(uint32_t sum)
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return ~sum & 0xffff;
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iphdr ip;
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct udphdr udp;
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iovec iov[3];
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t udpsum;
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t temp;
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct msghdr msghdr;
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct sockaddr_ll destaddr;
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.version = IPVERSION;
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.ihl = sizeof(ip) >> 2;
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.tos = 0;
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.id = 0;
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.frag_off = 0;
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.ttl = IPDEFTTL;
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.protocol = IPPROTO_UDP;
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.check = 0;
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.saddr = saddr;
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.daddr = daddr;
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.source = htons(sport);
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.dest = htons(dport);
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.len = htons(sizeof(udp) + size);
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.check = 0;
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Calculate checksum for pseudo header */
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = htons(IPPROTO_UDP);
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&temp, sizeof(temp), udpsum);
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = udp.len;
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&temp, sizeof(temp), udpsum);
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Add in the checksum for the udp header */
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&udp, sizeof(udp), udpsum);
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Add in the checksum for the data */
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(msg, size, udpsum);
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.check = finish_sum(udpsum);
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_base = (char *)&ip;
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_len = sizeof(ip);
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[1].iov_base = (char *)&udp;
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[1].iov_len = sizeof(udp);
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[2].iov_base = (char *)msg;
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[2].iov_len = size;
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&destaddr, 0, sizeof(destaddr));
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_family = AF_PACKET;
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_protocol = htons(ETH_P_IP);
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_ifindex = if_index;
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_halen = ETH_ALEN;
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_name = &destaddr;
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_namelen = sizeof(destaddr);
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_iov = iov;
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_flags = 0;
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_control = 0;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_controllen = 0;
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return sendmsg(s, &msghdr, 0);
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint receive_packet(int s, struct dhcp_msg *msg)
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int nread;
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int is_valid;
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct dhcp_packet {
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct iphdr ip;
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct udphdr udp;
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct dhcp_msg dhcp;
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } packet;
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int dhcp_size;
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t sum;
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t temp;
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t saddr, daddr;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    nread = read(s, &packet, sizeof(packet));
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (nread < 0) {
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * The raw packet interface gives us all packets received by the
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * network interface. We need to filter out all packets that are
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * not meant for us.
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    is_valid = 0;
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) {
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1828d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Packet is too small (%d) to be a UDP datagram", nread);
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) {
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1868d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Not a valid IP packet");
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (nread < ntohs(packet.ip.tot_len)) {
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1908d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.ip.protocol != IPPROTO_UDP) {
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1948d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) {
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1988d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        is_valid = 1;
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!is_valid) {
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Seems like it's probably a valid DHCP packet */
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* validate IP header checksum */
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sum != 0) {
212ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("IP header checksum failure (0x%x)", packet.ip.check);
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Validate the UDP checksum.
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Since we don't need the IP header anymore, we "borrow" it
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * to construct the pseudo header used in the checksum calculation.
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    saddr = packet.ip.saddr;
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    daddr = packet.ip.daddr;
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    nread = ntohs(packet.ip.tot_len);
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&packet.ip, 0, sizeof(packet.ip));
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.saddr = saddr;
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.daddr = daddr;
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.protocol = IPPROTO_UDP;
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.tot_len = packet.udp.len;
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = packet.udp.check;
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.udp.check = 0;
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sum = finish_sum(checksum(&packet, nread, 0));
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.udp.check = temp;
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (temp != sum) {
234ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(msg, &packet.dhcp, dhcp_size);
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return dhcp_size;
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
240