1 /* vi: set sw=4 ts=4: */
3 * Copyright (C) 2011 Denys Vlasenko.
5 * Licensed under GPLv2, see file LICENSE in this source tree.
10 #include <netinet/in.h>
11 #include <netinet/if_ether.h>
12 #include <netpacket/packet.h>
14 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
15 void FAST_FUNC
d6_dump_packet(struct d6_packet
*packet
)
24 //*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
25 //bb_error_msg(" chaddr %s", buf);
29 int FAST_FUNC
d6_recv_kernel_packet(struct in6_addr
*peer_ipv6
31 , struct d6_packet
*packet
, int fd
)
35 memset(packet
, 0, sizeof(*packet
));
36 bytes
= safe_read(fd
, packet
, sizeof(*packet
));
38 log1("packet read error, ignoring");
39 return bytes
; /* returns -1 */
42 if (bytes
< offsetof(struct d6_packet
, d6_options
)) {
43 bb_error_msg("packet with bad magic, ignoring");
46 log1("received %s", "a packet");
47 d6_dump_packet(packet
);
52 /* Construct a ipv6+udp header for a packet, send packet */
53 int FAST_FUNC
d6_send_raw_packet(
54 struct d6_packet
*d6_pkt
, unsigned d6_pkt_size
,
55 struct in6_addr
*src_ipv6
, int source_port
,
56 struct in6_addr
*dst_ipv6
, int dest_port
, const uint8_t *dest_arp
,
59 struct sockaddr_ll dest_sll
;
60 struct ip6_udp_d6_packet packet
;
65 fd
= socket(PF_PACKET
, SOCK_DGRAM
, htons(ETH_P_IPV6
));
71 memset(&dest_sll
, 0, sizeof(dest_sll
));
72 memset(&packet
, 0, offsetof(struct ip6_udp_d6_packet
, data
));
73 packet
.data
= *d6_pkt
; /* struct copy */
75 dest_sll
.sll_family
= AF_PACKET
;
76 dest_sll
.sll_protocol
= htons(ETH_P_IPV6
);
77 dest_sll
.sll_ifindex
= ifindex
;
78 dest_sll
.sll_halen
= 6;
79 memcpy(dest_sll
.sll_addr
, dest_arp
, 6);
81 if (bind(fd
, (struct sockaddr
*)&dest_sll
, sizeof(dest_sll
)) < 0) {
86 packet
.ip6
.ip6_vfc
= (6 << 4); /* 4 bits version, top 4 bits of tclass */
88 packet
.ip6
.ip6_src
= *src_ipv6
; /* struct copy */
89 packet
.ip6
.ip6_dst
= *dst_ipv6
; /* struct copy */
90 packet
.udp
.source
= htons(source_port
);
91 packet
.udp
.dest
= htons(dest_port
);
92 /* size, excluding IP header: */
93 packet
.udp
.len
= htons(sizeof(struct udphdr
) + d6_pkt_size
);
94 packet
.ip6
.ip6_plen
= packet
.udp
.len
;
96 * Someone was smoking weed (at least) while inventing UDP checksumming:
97 * UDP checksum skips first four bytes of IPv6 header.
98 * 'next header' field should be summed as if it is one more byte
99 * to the right, therefore we write its value (IPPROTO_UDP)
100 * into ip6_hlim, and its 'real' location remains zero-filled for now.
102 packet
.ip6
.ip6_hlim
= IPPROTO_UDP
;
103 packet
.udp
.check
= inet_cksum(
104 (uint16_t *)&packet
+ 2,
105 offsetof(struct ip6_udp_d6_packet
, data
) - 4 + d6_pkt_size
107 /* fix 'hop limit' and 'next header' after UDP checksumming */
108 packet
.ip6
.ip6_hlim
= 1; /* observed Windows machines to use hlim=1 */
109 packet
.ip6
.ip6_nxt
= IPPROTO_UDP
;
111 d6_dump_packet(d6_pkt
);
112 result
= sendto(fd
, &packet
, offsetof(struct ip6_udp_d6_packet
, data
) + d6_pkt_size
,
114 (struct sockaddr
*) &dest_sll
, sizeof(dest_sll
)
121 bb_perror_msg(msg
, "PACKET");
126 /* Let the kernel do all the work for packet generation */
127 int FAST_FUNC
d6_send_kernel_packet(
128 struct d6_packet
*d6_pkt
, unsigned d6_pkt_size
,
129 struct in6_addr
*src_ipv6
, int source_port
,
130 struct in6_addr
*dst_ipv6
, int dest_port
)
132 struct sockaddr_in6 sa
;
137 fd
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
142 setsockopt_reuseaddr(fd
);
144 memset(&sa
, 0, sizeof(sa
));
145 sa
.sin6_family
= AF_INET6
;
146 sa
.sin6_port
= htons(source_port
);
147 sa
.sin6_addr
= *src_ipv6
; /* struct copy */
148 if (bind(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
153 memset(&sa
, 0, sizeof(sa
));
154 sa
.sin6_family
= AF_INET6
;
155 sa
.sin6_port
= htons(dest_port
);
156 sa
.sin6_addr
= *dst_ipv6
; /* struct copy */
157 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
162 d6_dump_packet(d6_pkt
);
163 result
= safe_write(fd
, d6_pkt
, d6_pkt_size
);
169 bb_perror_msg(msg
, "UDP");