~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to ipconfig/packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * ipconfig/packet.c
3
 
 *
4
 
 * Packet socket handling glue.
5
 
 */
6
 
#include <sys/types.h>
7
 
#include <sys/socket.h>
8
 
#include <stdio.h>
9
 
#include <stdlib.h>
10
 
#include <string.h>
11
 
#include <unistd.h>
12
 
#include <net/if_packet.h>
13
 
#include <netinet/if_ether.h>
14
 
#include <netinet/in.h>
15
 
#include <netpacket/packet.h>
16
 
#include <asm/byteorder.h>
17
 
#include <arpa/inet.h>
18
 
#include <netinet/ip.h>
19
 
#include <netinet/udp.h>
20
 
 
21
 
#include "ipconfig.h"
22
 
#include "netdev.h"
23
 
#include "packet.h"
24
 
 
25
 
static int pkt_fd = -1;
26
 
 
27
 
__u16 cfg_local_port = LOCAL_PORT;
28
 
__u16 cfg_remote_port = REMOTE_PORT;
29
 
 
30
 
int packet_open(void)
31
 
{
32
 
        int fd, one = 1;
33
 
 
34
 
        if (pkt_fd != -1)
35
 
                return pkt_fd;
36
 
        
37
 
        /*
38
 
         * Get a PACKET socket for IP traffic.
39
 
         */
40
 
        fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
41
 
        if (fd == -1) {
42
 
                perror("socket");
43
 
                return -1;
44
 
        }
45
 
 
46
 
        /*
47
 
         * We want to broadcast
48
 
         */
49
 
        if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one,
50
 
                       sizeof(one)) == -1) {
51
 
                perror("SO_BROADCAST");
52
 
                close(fd);
53
 
                fd = -1;
54
 
        }
55
 
 
56
 
        pkt_fd = fd;
57
 
 
58
 
        return fd;
59
 
}
60
 
 
61
 
void packet_close(void)
62
 
{
63
 
        close(pkt_fd);
64
 
        pkt_fd = -1;
65
 
}
66
 
 
67
 
static unsigned int ip_checksum(__u16 *hdr, int len)
68
 
{
69
 
        unsigned int chksum = 0;
70
 
 
71
 
        while (len) {
72
 
                chksum += *hdr++;
73
 
                chksum += *hdr++;
74
 
                len--;
75
 
        }
76
 
        chksum = (chksum & 0xffff) + (chksum >> 16);
77
 
        chksum = (chksum & 0xffff) + (chksum >> 16);
78
 
        return (~chksum) & 0xffff;
79
 
}
80
 
 
81
 
struct header {
82
 
        struct iphdr    ip;
83
 
        struct udphdr   udp;
84
 
} __attribute__((packed));
85
 
 
86
 
static struct header ipudp_hdrs = {
87
 
        .ip = {
88
 
                .ihl            = 5,
89
 
                .version        = IPVERSION,
90
 
                .frag_off       = __constant_htons(IP_DF),
91
 
                .ttl            = 64,
92
 
                .protocol       = IPPROTO_UDP,
93
 
                .saddr          = INADDR_ANY,
94
 
                .daddr          = INADDR_BROADCAST,
95
 
        },
96
 
        .udp = {
97
 
                .source         = __constant_htons(LOCAL_PORT),
98
 
                .dest           = __constant_htons(REMOTE_PORT),
99
 
                .len            = 0,
100
 
                .check          = 0,
101
 
        },
102
 
};
103
 
 
104
 
#ifdef IPC_DEBUG                /* Only used by DEBUG(()) */
105
 
static char *ntoa(__u32 addr)
106
 
{
107
 
        struct in_addr in = { addr };
108
 
        return inet_ntoa(in);
109
 
}
110
 
#endif
111
 
 
112
 
/*
113
 
 * Send a packet.  The options are listed in iov[1...iov_len].
114
 
 * iov[0] is reserved for the bootp packet header.
115
 
 */
116
 
int packet_send(struct netdev *dev, struct iovec *iov, int iov_len)
117
 
{
118
 
        struct sockaddr_ll sll;
119
 
        struct msghdr msg = {
120
 
                .msg_name       = &sll,
121
 
                .msg_namelen    = sizeof(sll),
122
 
                .msg_iov        = iov,
123
 
                .msg_iovlen     = iov_len,
124
 
                .msg_control    = NULL,
125
 
                .msg_controllen = 0,
126
 
                .msg_flags      = 0
127
 
        };
128
 
        int i, len = 0;
129
 
 
130
 
        if (cfg_local_port != LOCAL_PORT) {
131
 
                ipudp_hdrs.udp.source = htons(cfg_local_port);
132
 
                ipudp_hdrs.udp.dest = htons(cfg_remote_port);
133
 
        }
134
 
        
135
 
        DEBUG(("\n   udp src %d dst %d", ntohs(ipudp_hdrs.udp.source),
136
 
               ntohs(ipudp_hdrs.udp.dest)));
137
 
 
138
 
        DEBUG(("\n   ip src %s ", ntoa(ipudp_hdrs.ip.saddr)));
139
 
        DEBUG(("dst %s ", ntoa(ipudp_hdrs.ip.daddr)));
140
 
 
141
 
        /*
142
 
         * Glue in the ip+udp header iovec
143
 
         */
144
 
        iov[0].iov_base = &ipudp_hdrs;
145
 
        iov[0].iov_len = sizeof(struct header);
146
 
 
147
 
        for (i = 0; i < iov_len; i++)
148
 
                len += iov[i].iov_len;
149
 
 
150
 
        sll.sll_family   = AF_PACKET;
151
 
        sll.sll_protocol = htons(ETH_P_IP);
152
 
        sll.sll_ifindex  = dev->ifindex;
153
 
        sll.sll_hatype   = dev->hwtype;
154
 
        sll.sll_pkttype  = PACKET_BROADCAST;
155
 
        sll.sll_halen    = dev->hwlen;
156
 
        memcpy(sll.sll_addr, dev->hwbrd, dev->hwlen);
157
 
 
158
 
        ipudp_hdrs.ip.tot_len   = htons(len);
159
 
        ipudp_hdrs.ip.check     = 0;
160
 
        ipudp_hdrs.ip.check     = ip_checksum((__u16 *)&ipudp_hdrs.ip,
161
 
                                                ipudp_hdrs.ip.ihl);
162
 
 
163
 
        ipudp_hdrs.udp.len      = htons(len - sizeof(struct iphdr));
164
 
 
165
 
        DEBUG(("\n   bytes %d\n", len));
166
 
        
167
 
        return sendmsg(pkt_fd, &msg, 0);
168
 
}
169
 
 
170
 
int packet_peek(int *ifindex)
171
 
{
172
 
        struct sockaddr_ll sll;
173
 
        struct iphdr iph;
174
 
        int ret, sllen = sizeof(struct sockaddr_ll);
175
 
 
176
 
        /*
177
 
         * Peek at the IP header.
178
 
         */
179
 
        ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr),
180
 
                       MSG_PEEK, (struct sockaddr *)&sll, &sllen);
181
 
        if (ret == -1)
182
 
                return -1;
183
 
 
184
 
        if (sll.sll_family != AF_PACKET)
185
 
                goto discard_pkt;
186
 
 
187
 
        if (iph.ihl < 5 || iph.version != IPVERSION)
188
 
                goto discard_pkt;
189
 
 
190
 
        *ifindex = sll.sll_ifindex;
191
 
 
192
 
        return 0;
193
 
 
194
 
 discard_pkt:
195
 
        packet_discard();
196
 
        return 0;
197
 
}
198
 
 
199
 
void packet_discard(void)
200
 
{
201
 
        struct iphdr iph;
202
 
        struct sockaddr_ll sll;
203
 
        socklen_t sllen = sizeof(sll);
204
 
        
205
 
        recvfrom(pkt_fd, &iph, sizeof(iph), 0,
206
 
                 (struct sockaddr *) &sll, &sllen);
207
 
}
208
 
 
209
 
/*
210
 
 * Receive a bootp packet.  The options are listed in iov[1...iov_len].
211
 
 * iov[0] must point to the bootp packet header.
212
 
 */
213
 
int packet_recv(struct iovec *iov, int iov_len)
214
 
{
215
 
        struct iphdr *ip, iph;
216
 
        struct udphdr *udp;
217
 
        struct msghdr msg = {
218
 
                .msg_name       = NULL,
219
 
                .msg_namelen    = 0,
220
 
                .msg_iov        = iov,
221
 
                .msg_iovlen     = iov_len,
222
 
                .msg_control    = NULL,
223
 
                .msg_controllen = 0,
224
 
                .msg_flags      = 0
225
 
        };
226
 
        int ret, iphl;
227
 
 
228
 
        ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr),
229
 
                       MSG_PEEK, NULL, NULL);
230
 
        if (ret == -1)
231
 
                return -1;
232
 
 
233
 
        if (iph.ihl < 5 || iph.version != IPVERSION)
234
 
                goto discard_pkt;
235
 
 
236
 
        iphl = iph.ihl * 4;
237
 
 
238
 
        ip = malloc(iphl + sizeof(struct udphdr));
239
 
        if (!ip)
240
 
                goto discard_pkt;
241
 
 
242
 
        udp = (struct udphdr *)((char *)ip + iphl);
243
 
 
244
 
        iov[0].iov_base = ip;
245
 
        iov[0].iov_len = iphl + sizeof(struct udphdr);
246
 
 
247
 
        ret = recvmsg(pkt_fd, &msg, 0);
248
 
        if (ret == -1)
249
 
                goto free_pkt;
250
 
 
251
 
        DEBUG(("<- bytes %d ", ret));
252
 
 
253
 
        if (ip_checksum((__u16 *)ip, ip->ihl) != 0)
254
 
                goto free_pkt;
255
 
 
256
 
        DEBUG(("\n   ip src %s ", ntoa(ip->saddr)));
257
 
        DEBUG(("dst %s ", ntoa(ip->daddr)));
258
 
 
259
 
        if (ntohs(ip->tot_len) > ret || ip->protocol != IPPROTO_UDP)
260
 
                goto free_pkt;
261
 
 
262
 
        ret -= 4 * ip->ihl;
263
 
 
264
 
        DEBUG(("\n   udp src %d dst %d ", ntohs(udp->source),
265
 
               ntohs(udp->dest)));
266
 
        
267
 
        if (udp->source != htons(cfg_remote_port) ||
268
 
            udp->dest != htons(cfg_local_port))
269
 
                goto free_pkt;
270
 
 
271
 
        if (ntohs(udp->len) > ret)
272
 
                goto free_pkt;
273
 
 
274
 
        ret -= sizeof(struct udphdr);
275
 
 
276
 
        free(ip);
277
 
 
278
 
        return ret;
279
 
 
280
 
 free_pkt:
281
 
        free(ip);
282
 
        return 0;
283
 
 
284
 
 discard_pkt:
285
 
        DEBUG(("discarded\n"));
286
 
        packet_discard();
287
 
        return 0;
288
 
}