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>
18a744b05984a963966cec08758ffe582d241be9d7Elliott Hughes#include <string.h>
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/uio.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/socket.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/in.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/ip.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/udp.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <linux/if_packet.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <linux/if_ether.h>
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#ifdef ANDROID
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define LOG_TAG "DHCP"
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/log.h>
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#else
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
358d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block#define ALOGD printf
36ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block#define ALOGW printf
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "dhcpmsg.h"
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint fatal();
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
43a5db95da3801cd82df80c41996b1e6f69a9acecfEdwin Vaneint open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
45a5d5d8477357078a636c7e0d1e80c128cfd25262Andreas Gampe    int s;
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct sockaddr_ll bindaddr;
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("socket(PF_PACKET)");
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&bindaddr, 0, sizeof(bindaddr));
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_family = AF_PACKET;
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_protocol = htons(ETH_P_IP);
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_halen = ETH_ALEN;
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bindaddr.sll_ifindex = if_index;
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("Cannot bind raw socket to interface");
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return s;
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t *up = (uint16_t *)buffer;
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t sum = startsum;
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t upper16;
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (count > 1) {
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum += *up++;
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        count -= 2;
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (count > 0) {
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum += (uint16_t) *(uint8_t *)up;
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while ((upper16 = (sum >> 16)) != 0) {
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sum = (sum & 0xffff) + upper16;
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return sum;
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic uint32_t finish_sum(uint32_t sum)
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return ~sum & 0xffff;
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iphdr ip;
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct udphdr udp;
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iovec iov[3];
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t udpsum;
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t temp;
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct msghdr msghdr;
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct sockaddr_ll destaddr;
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.version = IPVERSION;
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.ihl = sizeof(ip) >> 2;
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.tos = 0;
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.id = 0;
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.frag_off = 0;
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.ttl = IPDEFTTL;
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.protocol = IPPROTO_UDP;
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.check = 0;
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.saddr = saddr;
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.daddr = daddr;
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.source = htons(sport);
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.dest = htons(dport);
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.len = htons(sizeof(udp) + size);
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.check = 0;
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Calculate checksum for pseudo header */
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = htons(IPPROTO_UDP);
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&temp, sizeof(temp), udpsum);
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = udp.len;
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&temp, sizeof(temp), udpsum);
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Add in the checksum for the udp header */
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(&udp, sizeof(udp), udpsum);
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Add in the checksum for the data */
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udpsum = checksum(msg, size, udpsum);
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    udp.check = finish_sum(udpsum);
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_base = (char *)&ip;
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_len = sizeof(ip);
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[1].iov_base = (char *)&udp;
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[1].iov_len = sizeof(udp);
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[2].iov_base = (char *)msg;
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[2].iov_len = size;
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&destaddr, 0, sizeof(destaddr));
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_family = AF_PACKET;
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_protocol = htons(ETH_P_IP);
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_ifindex = if_index;
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    destaddr.sll_halen = ETH_ALEN;
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_name = &destaddr;
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_namelen = sizeof(destaddr);
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_iov = iov;
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_flags = 0;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_control = 0;
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msghdr.msg_controllen = 0;
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return sendmsg(s, &msghdr, 0);
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint receive_packet(int s, struct dhcp_msg *msg)
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int nread;
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int is_valid;
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct dhcp_packet {
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct iphdr ip;
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct udphdr udp;
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct dhcp_msg dhcp;
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } packet;
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int dhcp_size;
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t sum;
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint16_t temp;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t saddr, daddr;
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    nread = read(s, &packet, sizeof(packet));
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (nread < 0) {
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * The raw packet interface gives us all packets received by the
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * network interface. We need to filter out all packets that are
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * not meant for us.
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    is_valid = 0;
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) {
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1838d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Packet is too small (%d) to be a UDP datagram", nread);
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) {
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1878d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Not a valid IP packet");
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (nread < ntohs(packet.ip.tot_len)) {
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1918d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.ip.protocol != IPPROTO_UDP) {
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1958d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) {
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
1998d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        is_valid = 1;
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!is_valid) {
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Seems like it's probably a valid DHCP packet */
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* validate IP header checksum */
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sum != 0) {
213ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("IP header checksum failure (0x%x)", packet.ip.check);
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Validate the UDP checksum.
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Since we don't need the IP header anymore, we "borrow" it
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * to construct the pseudo header used in the checksum calculation.
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    saddr = packet.ip.saddr;
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    daddr = packet.ip.daddr;
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    nread = ntohs(packet.ip.tot_len);
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(&packet.ip, 0, sizeof(packet.ip));
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.saddr = saddr;
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.daddr = daddr;
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.protocol = IPPROTO_UDP;
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.ip.tot_len = packet.udp.len;
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    temp = packet.udp.check;
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.udp.check = 0;
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sum = finish_sum(checksum(&packet, nread, 0));
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet.udp.check = temp;
2341c87ae05b337f789b2e56bbb273758dfb12fb2efAjay Dudani    if (!sum)
2351c87ae05b337f789b2e56bbb273758dfb12fb2efAjay Dudani        sum = finish_sum(sum);
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (temp != sum) {
237ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(msg, &packet.dhcp, dhcp_size);
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return dhcp_size;
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
243