Added CONFIG_CLEAR and CONFIG_RESET to config.maemo
[busybox4maemo] / networking / udhcp / clientsocket.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * clientsocket.c -- DHCP client socket creation
4  *
5  * udhcp client
6  *
7  * Russ Dill <Russ.Dill@asu.edu> July 2001
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <features.h>
25 #include <asm/types.h>
26 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
27 #include <netpacket/packet.h>
28 #include <net/ethernet.h>
29 #else
30 #include <linux/if_packet.h>
31 #include <linux/if_ether.h>
32 #endif
33 #include <linux/filter.h>
34
35 #include "common.h"
36 #include "dhcpd.h"
37 #include "dhcpc.h"
38
39 int raw_socket(int ifindex)
40 {
41         int fd;
42         struct sockaddr_ll sock;
43
44         /*
45          * Comment:
46          *
47          *      I've selected not to see LL header, so BPF doesn't see it, too.
48          *      The filter may also pass non-IP and non-ARP packets, but we do
49          *      a more complete check when receiving the message in userspace.
50          *
51          * and filter shamelessly stolen from:
52          *
53          *      http://www.flamewarmaster.de/software/dhcpclient/
54          *
55          * There are a few other interesting ideas on that page (look under
56          * "Motivation").  Use of netlink events is most interesting.  Think
57          * of various network servers listening for events and reconfiguring.
58          * That would obsolete sending HUP signals and/or make use of restarts.
59          *
60          * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
61          * License: GPL v2.
62          *
63          * TODO: make conditional?
64          */
65 #define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
66         static const struct sock_filter filter_instr[] = {
67                 /* check for udp */
68                 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
69                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
70                 /* ugly check for arp on ethernet-like and IPv4 */
71                 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
72                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
73                 /* skip IP header */
74                 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
75                 /* check udp source and destination ports */
76                 BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
77                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
78                 /* returns */
79                 BPF_STMT(BPF_RET|BPF_K, (~(uint32_t)0) ),               /* L3: pass */
80                 BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
81         };
82         static const struct sock_fprog filter_prog = {
83                 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
84                 /* casting const away: */
85                 .filter = (struct sock_filter *) filter_instr,
86         };
87
88         DEBUG("opening raw socket on ifindex %d", ifindex);
89
90         fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
91         DEBUG("got raw socket fd %d", fd);
92
93         if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
94                 /* Use only if standard ports are in use */
95                 /* Ignoring error (kernel may lack support for this) */
96                 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
97                                 sizeof(filter_prog)) >= 0)
98                         DEBUG("attached filter to raw socket fd %d", fd);
99         }
100
101         sock.sll_family = AF_PACKET;
102         sock.sll_protocol = htons(ETH_P_IP);
103         sock.sll_ifindex = ifindex;
104         xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
105         DEBUG("bound to raw socket fd %d", fd);
106
107         return fd;
108 }