1*ef8d499eSDavid van Moolenbroek /* LWIP service - rawsock.c - RAW sockets */
2*ef8d499eSDavid van Moolenbroek /*
3*ef8d499eSDavid van Moolenbroek * For IPv6 sockets, this module attempts to implement a part of RFC 3542, but
4*ef8d499eSDavid van Moolenbroek * currently not more than what is supported by lwIP and/or what is expected by
5*ef8d499eSDavid van Moolenbroek * a handful of standard utilities (dhcpcd, ping6, traceroute6..).
6*ef8d499eSDavid van Moolenbroek *
7*ef8d499eSDavid van Moolenbroek * For general understanding, be aware that IPv4 raw sockets always receive
8*ef8d499eSDavid van Moolenbroek * packets including the IP header, and may be used to send packets including
9*ef8d499eSDavid van Moolenbroek * the IP header if IP_HDRINCL is set, while IPv6 raw sockets always send and
10*ef8d499eSDavid van Moolenbroek * receive actual payloads only, using ancillary (control) data to set and
11*ef8d499eSDavid van Moolenbroek * retrieve per-packet IP header fields.
12*ef8d499eSDavid van Moolenbroek *
13*ef8d499eSDavid van Moolenbroek * For packet headers we follow general BSD semantics. For example, some IPv4
14*ef8d499eSDavid van Moolenbroek * header fields are swapped both when sending and when receiving. Also, like
15*ef8d499eSDavid van Moolenbroek * on NetBSD, IPPROTO_RAW is not a special value in any way.
16*ef8d499eSDavid van Moolenbroek */
17*ef8d499eSDavid van Moolenbroek
18*ef8d499eSDavid van Moolenbroek #include "lwip.h"
19*ef8d499eSDavid van Moolenbroek #include "ifaddr.h"
20*ef8d499eSDavid van Moolenbroek #include "pktsock.h"
21*ef8d499eSDavid van Moolenbroek
22*ef8d499eSDavid van Moolenbroek #include "lwip/raw.h"
23*ef8d499eSDavid van Moolenbroek #include "lwip/inet_chksum.h"
24*ef8d499eSDavid van Moolenbroek
25*ef8d499eSDavid van Moolenbroek #include <net/route.h>
26*ef8d499eSDavid van Moolenbroek #include <netinet/icmp6.h>
27*ef8d499eSDavid van Moolenbroek #include <netinet/ip.h>
28*ef8d499eSDavid van Moolenbroek #include <netinet/in_pcb.h>
29*ef8d499eSDavid van Moolenbroek
30*ef8d499eSDavid van Moolenbroek /* The number of RAW sockets. Inherited from the lwIP configuration. */
31*ef8d499eSDavid van Moolenbroek #define NR_RAWSOCK MEMP_NUM_RAW_PCB
32*ef8d499eSDavid van Moolenbroek
33*ef8d499eSDavid van Moolenbroek /*
34*ef8d499eSDavid van Moolenbroek * Outgoing packets are not getting buffered, so the send buffer size simply
35*ef8d499eSDavid van Moolenbroek * determines the maximum size for sent packets. The send buffer maximum is
36*ef8d499eSDavid van Moolenbroek * therefore limited to the maximum size of a single packet (64K-1 bytes),
37*ef8d499eSDavid van Moolenbroek * which is already enforced by lwIP's 16-bit length parameter to pbuf_alloc().
38*ef8d499eSDavid van Moolenbroek *
39*ef8d499eSDavid van Moolenbroek * The actual transmission may enforce a lower limit, though. The full packet
40*ef8d499eSDavid van Moolenbroek * size must not exceed the same 64K-1 limit, and that includes any headers
41*ef8d499eSDavid van Moolenbroek * that still have to be prepended to the given packet. The size of those
42*ef8d499eSDavid van Moolenbroek * headers depends on the socket type (IPv4/IPv6) and the IP_HDRINCL setting.
43*ef8d499eSDavid van Moolenbroek *
44*ef8d499eSDavid van Moolenbroek * The default is equal to the maximum here, because if a (by definition,
45*ef8d499eSDavid van Moolenbroek * privileged) application wishes to send large raw packets, it probably has a
46*ef8d499eSDavid van Moolenbroek * good reason, and we do not want to get in its way.
47*ef8d499eSDavid van Moolenbroek */
48*ef8d499eSDavid van Moolenbroek #define RAW_MAX_PAYLOAD (UINT16_MAX)
49*ef8d499eSDavid van Moolenbroek
50*ef8d499eSDavid van Moolenbroek #define RAW_SNDBUF_MIN 1 /* minimum RAW send buffer size */
51*ef8d499eSDavid van Moolenbroek #define RAW_SNDBUF_DEF RAW_MAX_PAYLOAD /* default RAW send buffer size */
52*ef8d499eSDavid van Moolenbroek #define RAW_SNDBUF_MAX RAW_MAX_PAYLOAD /* maximum RAW send buffer size */
53*ef8d499eSDavid van Moolenbroek #define RAW_RCVBUF_MIN MEMPOOL_BUFSIZE /* minimum RAW receive buffer size */
54*ef8d499eSDavid van Moolenbroek #define RAW_RCVBUF_DEF 32768 /* default RAW receive buffer size */
55*ef8d499eSDavid van Moolenbroek #define RAW_RCVBUF_MAX 65536 /* maximum RAW receive buffer size */
56*ef8d499eSDavid van Moolenbroek
57*ef8d499eSDavid van Moolenbroek static struct rawsock {
58*ef8d499eSDavid van Moolenbroek struct pktsock raw_pktsock; /* packet socket object */
59*ef8d499eSDavid van Moolenbroek struct raw_pcb *raw_pcb; /* lwIP RAW control block */
60*ef8d499eSDavid van Moolenbroek TAILQ_ENTRY(rawsock) raw_next; /* next in active/free list */
61*ef8d499eSDavid van Moolenbroek struct icmp6_filter raw_icmp6filter; /* ICMPv6 type filter */
62*ef8d499eSDavid van Moolenbroek } raw_array[NR_RAWSOCK];
63*ef8d499eSDavid van Moolenbroek
64*ef8d499eSDavid van Moolenbroek static TAILQ_HEAD(, rawsock) raw_freelist; /* list of free RAW sockets */
65*ef8d499eSDavid van Moolenbroek static TAILQ_HEAD(, rawsock) raw_activelist; /* list, in-use RAW sockets */
66*ef8d499eSDavid van Moolenbroek
67*ef8d499eSDavid van Moolenbroek static const struct sockevent_ops rawsock_ops;
68*ef8d499eSDavid van Moolenbroek
69*ef8d499eSDavid van Moolenbroek #define rawsock_get_sock(raw) (ipsock_get_sock(rawsock_get_ipsock(raw)))
70*ef8d499eSDavid van Moolenbroek #define rawsock_get_ipsock(raw) (pktsock_get_ipsock(&(raw)->raw_pktsock))
71*ef8d499eSDavid van Moolenbroek #define rawsock_is_ipv6(raw) (ipsock_is_ipv6(rawsock_get_ipsock(raw)))
72*ef8d499eSDavid van Moolenbroek #define rawsock_is_v6only(raw) (ipsock_is_v6only(rawsock_get_ipsock(raw)))
73*ef8d499eSDavid van Moolenbroek #define rawsock_is_conn(raw) \
74*ef8d499eSDavid van Moolenbroek (raw_flags((raw)->raw_pcb) & RAW_FLAGS_CONNECTED)
75*ef8d499eSDavid van Moolenbroek #define rawsock_is_hdrincl(raw) \
76*ef8d499eSDavid van Moolenbroek (raw_flags((raw)->raw_pcb) & RAW_FLAGS_HDRINCL)
77*ef8d499eSDavid van Moolenbroek
78*ef8d499eSDavid van Moolenbroek static ssize_t rawsock_pcblist(struct rmib_call *, struct rmib_node *,
79*ef8d499eSDavid van Moolenbroek struct rmib_oldp *, struct rmib_newp *);
80*ef8d499eSDavid van Moolenbroek
81*ef8d499eSDavid van Moolenbroek /* The CTL_NET {PF_INET,PF_INET6} IPPROTO_RAW subtree. */
82*ef8d499eSDavid van Moolenbroek /* All dynamically numbered; the sendspace/recvspace entries are ours. */
83*ef8d499eSDavid van Moolenbroek static struct rmib_node net_inet_raw_table[] = {
84*ef8d499eSDavid van Moolenbroek RMIB_INT(RMIB_RO, RAW_SNDBUF_DEF, "sendspace",
85*ef8d499eSDavid van Moolenbroek "Default RAW send buffer size"),
86*ef8d499eSDavid van Moolenbroek RMIB_INT(RMIB_RO, RAW_RCVBUF_DEF, "recvspace",
87*ef8d499eSDavid van Moolenbroek "Default RAW receive buffer size"),
88*ef8d499eSDavid van Moolenbroek RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, rawsock_pcblist, "pcblist",
89*ef8d499eSDavid van Moolenbroek "RAW IP protocol control block list"),
90*ef8d499eSDavid van Moolenbroek };
91*ef8d499eSDavid van Moolenbroek
92*ef8d499eSDavid van Moolenbroek static struct rmib_node net_inet_raw_node =
93*ef8d499eSDavid van Moolenbroek RMIB_NODE(RMIB_RO, net_inet_raw_table, "raw", "RAW IPv4 settings");
94*ef8d499eSDavid van Moolenbroek static struct rmib_node net_inet6_raw6_node =
95*ef8d499eSDavid van Moolenbroek RMIB_NODE(RMIB_RO, net_inet_raw_table, "raw6", "RAW IPv6 settings");
96*ef8d499eSDavid van Moolenbroek
97*ef8d499eSDavid van Moolenbroek /*
98*ef8d499eSDavid van Moolenbroek * Initialize the raw sockets module.
99*ef8d499eSDavid van Moolenbroek */
100*ef8d499eSDavid van Moolenbroek void
rawsock_init(void)101*ef8d499eSDavid van Moolenbroek rawsock_init(void)
102*ef8d499eSDavid van Moolenbroek {
103*ef8d499eSDavid van Moolenbroek unsigned int slot;
104*ef8d499eSDavid van Moolenbroek
105*ef8d499eSDavid van Moolenbroek /* Initialize the list of free RAW sockets. */
106*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&raw_freelist);
107*ef8d499eSDavid van Moolenbroek
108*ef8d499eSDavid van Moolenbroek for (slot = 0; slot < __arraycount(raw_array); slot++)
109*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&raw_freelist, &raw_array[slot], raw_next);
110*ef8d499eSDavid van Moolenbroek
111*ef8d499eSDavid van Moolenbroek /* Initialize the list of active RAW sockets. */
112*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&raw_activelist);
113*ef8d499eSDavid van Moolenbroek
114*ef8d499eSDavid van Moolenbroek /* Register the net.inet.raw and net.inet6.raw6 RMIB subtrees. */
115*ef8d499eSDavid van Moolenbroek mibtree_register_inet(PF_INET, IPPROTO_RAW, &net_inet_raw_node);
116*ef8d499eSDavid van Moolenbroek mibtree_register_inet(PF_INET6, IPPROTO_RAW, &net_inet6_raw6_node);
117*ef8d499eSDavid van Moolenbroek }
118*ef8d499eSDavid van Moolenbroek
119*ef8d499eSDavid van Moolenbroek /*
120*ef8d499eSDavid van Moolenbroek * Check whether the given arrived IPv6 packet is fit to be received on the
121*ef8d499eSDavid van Moolenbroek * given raw socket.
122*ef8d499eSDavid van Moolenbroek */
123*ef8d499eSDavid van Moolenbroek static int
rawsock_check_v6(struct rawsock * raw,struct pbuf * pbuf)124*ef8d499eSDavid van Moolenbroek rawsock_check_v6(struct rawsock * raw, struct pbuf * pbuf)
125*ef8d499eSDavid van Moolenbroek {
126*ef8d499eSDavid van Moolenbroek uint8_t type;
127*ef8d499eSDavid van Moolenbroek
128*ef8d499eSDavid van Moolenbroek assert(rawsock_is_ipv6(raw));
129*ef8d499eSDavid van Moolenbroek
130*ef8d499eSDavid van Moolenbroek /*
131*ef8d499eSDavid van Moolenbroek * For ICMPv6 packets, test against the configured type filter.
132*ef8d499eSDavid van Moolenbroek */
133*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->protocol == IPPROTO_ICMPV6) {
134*ef8d499eSDavid van Moolenbroek if (pbuf->len < offsetof(struct icmp6_hdr, icmp6_dataun))
135*ef8d499eSDavid van Moolenbroek return FALSE;
136*ef8d499eSDavid van Moolenbroek
137*ef8d499eSDavid van Moolenbroek memcpy(&type, &((struct icmp6_hdr *)pbuf->payload)->icmp6_type,
138*ef8d499eSDavid van Moolenbroek sizeof(type));
139*ef8d499eSDavid van Moolenbroek
140*ef8d499eSDavid van Moolenbroek if (!ICMP6_FILTER_WILLPASS((int)type, &raw->raw_icmp6filter))
141*ef8d499eSDavid van Moolenbroek return FALSE;
142*ef8d499eSDavid van Moolenbroek }
143*ef8d499eSDavid van Moolenbroek
144*ef8d499eSDavid van Moolenbroek /*
145*ef8d499eSDavid van Moolenbroek * For ICMPv6 packets, or if IPV6_CHECKSUM is enabled, we have to
146*ef8d499eSDavid van Moolenbroek * verify the checksum of the packet before passing it to the user.
147*ef8d499eSDavid van Moolenbroek * This is costly, but it needs to be done and lwIP is not doing it for
148*ef8d499eSDavid van Moolenbroek * us (as of writing, anyway), even though it maintains the offset..
149*ef8d499eSDavid van Moolenbroek */
150*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->chksum_reqd &&
151*ef8d499eSDavid van Moolenbroek (pbuf->tot_len < raw->raw_pcb->chksum_offset + sizeof(uint16_t) ||
152*ef8d499eSDavid van Moolenbroek ip6_chksum_pseudo(pbuf, raw->raw_pcb->protocol, pbuf->tot_len,
153*ef8d499eSDavid van Moolenbroek ip6_current_src_addr(), ip6_current_dest_addr()) != 0)) {
154*ef8d499eSDavid van Moolenbroek return FALSE;
155*ef8d499eSDavid van Moolenbroek }
156*ef8d499eSDavid van Moolenbroek
157*ef8d499eSDavid van Moolenbroek /* No reason to filter out this packet. */
158*ef8d499eSDavid van Moolenbroek return TRUE;
159*ef8d499eSDavid van Moolenbroek }
160*ef8d499eSDavid van Moolenbroek
161*ef8d499eSDavid van Moolenbroek /*
162*ef8d499eSDavid van Moolenbroek * Adjust the given arrived IPv4 packet by changing the length and offset
163*ef8d499eSDavid van Moolenbroek * fields to host-byte order, as is done by the BSDs. This effectively mirrors
164*ef8d499eSDavid van Moolenbroek * the swapping part of the preparation done on IPv4 packets being sent if the
165*ef8d499eSDavid van Moolenbroek * IP_HDRINCL socket option is enabled.
166*ef8d499eSDavid van Moolenbroek */
167*ef8d499eSDavid van Moolenbroek static void
rawsock_adjust_v4(struct pbuf * pbuf)168*ef8d499eSDavid van Moolenbroek rawsock_adjust_v4(struct pbuf * pbuf)
169*ef8d499eSDavid van Moolenbroek {
170*ef8d499eSDavid van Moolenbroek struct ip_hdr *iphdr;
171*ef8d499eSDavid van Moolenbroek
172*ef8d499eSDavid van Moolenbroek if (pbuf->len < sizeof(struct ip_hdr))
173*ef8d499eSDavid van Moolenbroek return;
174*ef8d499eSDavid van Moolenbroek
175*ef8d499eSDavid van Moolenbroek iphdr = (struct ip_hdr *)pbuf->payload;
176*ef8d499eSDavid van Moolenbroek
177*ef8d499eSDavid van Moolenbroek /*
178*ef8d499eSDavid van Moolenbroek * W. Richard Stevens also mentions ip_id, but at least on NetBSD that
179*ef8d499eSDavid van Moolenbroek * field seems to be swapped neither when sending nor when receiving..
180*ef8d499eSDavid van Moolenbroek */
181*ef8d499eSDavid van Moolenbroek IPH_LEN(iphdr) = htons(IPH_LEN(iphdr));
182*ef8d499eSDavid van Moolenbroek IPH_OFFSET(iphdr) = htons(IPH_OFFSET(iphdr));
183*ef8d499eSDavid van Moolenbroek }
184*ef8d499eSDavid van Moolenbroek
185*ef8d499eSDavid van Moolenbroek /*
186*ef8d499eSDavid van Moolenbroek * A packet has arrived on a raw socket. Since the same packet may have to be
187*ef8d499eSDavid van Moolenbroek * delivered to multiple raw sockets, we always return 0 (= not consumed) from
188*ef8d499eSDavid van Moolenbroek * this function. As such, we must make a copy of the given packet if we want
189*ef8d499eSDavid van Moolenbroek * to keep it, and never free it.
190*ef8d499eSDavid van Moolenbroek */
191*ef8d499eSDavid van Moolenbroek static uint8_t
rawsock_input(void * arg,struct raw_pcb * pcb __unused,struct pbuf * psrc,const ip_addr_t * srcaddr)192*ef8d499eSDavid van Moolenbroek rawsock_input(void * arg, struct raw_pcb * pcb __unused, struct pbuf * psrc,
193*ef8d499eSDavid van Moolenbroek const ip_addr_t * srcaddr)
194*ef8d499eSDavid van Moolenbroek {
195*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)arg;
196*ef8d499eSDavid van Moolenbroek struct pbuf *pbuf;
197*ef8d499eSDavid van Moolenbroek int off, hdrlen;
198*ef8d499eSDavid van Moolenbroek
199*ef8d499eSDavid van Moolenbroek assert(raw->raw_pcb == pcb);
200*ef8d499eSDavid van Moolenbroek
201*ef8d499eSDavid van Moolenbroek /*
202*ef8d499eSDavid van Moolenbroek * If adding this packet would cause the receive buffer to go beyond
203*ef8d499eSDavid van Moolenbroek * the current limit, drop the new packet. This is just an estimation,
204*ef8d499eSDavid van Moolenbroek * because the copy we are about to make may not take the exact same
205*ef8d499eSDavid van Moolenbroek * amount of memory, due to the fact that 1) the pbuf we're given has
206*ef8d499eSDavid van Moolenbroek * an unknown set of headers in front of it, and 2) we need to store
207*ef8d499eSDavid van Moolenbroek * extra information in our copy. The return value of this call, if
208*ef8d499eSDavid van Moolenbroek * not -1, is the number of bytes we need to reserve to store that
209*ef8d499eSDavid van Moolenbroek * extra information.
210*ef8d499eSDavid van Moolenbroek */
211*ef8d499eSDavid van Moolenbroek if ((hdrlen = pktsock_test_input(&raw->raw_pktsock, psrc)) < 0)
212*ef8d499eSDavid van Moolenbroek return 0;
213*ef8d499eSDavid van Moolenbroek
214*ef8d499eSDavid van Moolenbroek /*
215*ef8d499eSDavid van Moolenbroek * Raw IPv6 sockets receive only the actual packet data, whereas raw
216*ef8d499eSDavid van Moolenbroek * IPv4 sockets receive the IP header as well.
217*ef8d499eSDavid van Moolenbroek */
218*ef8d499eSDavid van Moolenbroek if (ip_current_is_v6()) {
219*ef8d499eSDavid van Moolenbroek off = ip_current_header_tot_len();
220*ef8d499eSDavid van Moolenbroek
221*ef8d499eSDavid van Moolenbroek util_pbuf_header(psrc, -off);
222*ef8d499eSDavid van Moolenbroek
223*ef8d499eSDavid van Moolenbroek if (!rawsock_check_v6(raw, psrc)) {
224*ef8d499eSDavid van Moolenbroek util_pbuf_header(psrc, off);
225*ef8d499eSDavid van Moolenbroek
226*ef8d499eSDavid van Moolenbroek return 0;
227*ef8d499eSDavid van Moolenbroek }
228*ef8d499eSDavid van Moolenbroek } else {
229*ef8d499eSDavid van Moolenbroek /*
230*ef8d499eSDavid van Moolenbroek * For IPv6 sockets, drop the packet if it was sent as an IPv4
231*ef8d499eSDavid van Moolenbroek * packet and checksumming is enabled (this includes ICMPv6).
232*ef8d499eSDavid van Moolenbroek * Otherwise, the packet would bypass the above checks that we
233*ef8d499eSDavid van Moolenbroek * perform on IPv6 packets. Applications that want to use a
234*ef8d499eSDavid van Moolenbroek * dual-stack protocol with checksumming will have to do the
235*ef8d499eSDavid van Moolenbroek * checksum verification part themselves. Presumably the two
236*ef8d499eSDavid van Moolenbroek * different pseudoheaders would result in different checksums
237*ef8d499eSDavid van Moolenbroek * anyhow, so it would be useless to try to support that.
238*ef8d499eSDavid van Moolenbroek *
239*ef8d499eSDavid van Moolenbroek * Beyond that, for IPv4 packets on IPv6 sockets, hide the IPv4
240*ef8d499eSDavid van Moolenbroek * header.
241*ef8d499eSDavid van Moolenbroek */
242*ef8d499eSDavid van Moolenbroek if (rawsock_is_ipv6(raw)) {
243*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->chksum_reqd)
244*ef8d499eSDavid van Moolenbroek return 0;
245*ef8d499eSDavid van Moolenbroek
246*ef8d499eSDavid van Moolenbroek off = IP_HLEN;
247*ef8d499eSDavid van Moolenbroek
248*ef8d499eSDavid van Moolenbroek util_pbuf_header(psrc, -off);
249*ef8d499eSDavid van Moolenbroek } else
250*ef8d499eSDavid van Moolenbroek off = 0;
251*ef8d499eSDavid van Moolenbroek }
252*ef8d499eSDavid van Moolenbroek
253*ef8d499eSDavid van Moolenbroek /*
254*ef8d499eSDavid van Moolenbroek * We need to make a copy of the incoming packet. If we eat the one
255*ef8d499eSDavid van Moolenbroek * given to us, this will 1) stop any other raw sockets from getting
256*ef8d499eSDavid van Moolenbroek * the same packet, 2) allow a single raw socket to discard all TCP/UDP
257*ef8d499eSDavid van Moolenbroek * traffic, and 3) present us with a problem on how to store ancillary
258*ef8d499eSDavid van Moolenbroek * data. Raw sockets are not that performance critical so the extra
259*ef8d499eSDavid van Moolenbroek * copy -even when not always necessary- is not that big of a deal.
260*ef8d499eSDavid van Moolenbroek */
261*ef8d499eSDavid van Moolenbroek if ((pbuf = pchain_alloc(PBUF_RAW, hdrlen + psrc->tot_len)) == NULL) {
262*ef8d499eSDavid van Moolenbroek if (off > 0)
263*ef8d499eSDavid van Moolenbroek util_pbuf_header(psrc, off);
264*ef8d499eSDavid van Moolenbroek
265*ef8d499eSDavid van Moolenbroek return 0;
266*ef8d499eSDavid van Moolenbroek }
267*ef8d499eSDavid van Moolenbroek
268*ef8d499eSDavid van Moolenbroek util_pbuf_header(pbuf, -hdrlen);
269*ef8d499eSDavid van Moolenbroek
270*ef8d499eSDavid van Moolenbroek if (pbuf_copy(pbuf, psrc) != ERR_OK)
271*ef8d499eSDavid van Moolenbroek panic("unexpected pbuf copy failure");
272*ef8d499eSDavid van Moolenbroek
273*ef8d499eSDavid van Moolenbroek pbuf->flags |= psrc->flags & (PBUF_FLAG_LLMCAST | PBUF_FLAG_LLBCAST);
274*ef8d499eSDavid van Moolenbroek
275*ef8d499eSDavid van Moolenbroek if (off > 0)
276*ef8d499eSDavid van Moolenbroek util_pbuf_header(psrc, off);
277*ef8d499eSDavid van Moolenbroek
278*ef8d499eSDavid van Moolenbroek if (!rawsock_is_ipv6(raw))
279*ef8d499eSDavid van Moolenbroek rawsock_adjust_v4(pbuf);
280*ef8d499eSDavid van Moolenbroek
281*ef8d499eSDavid van Moolenbroek pktsock_input(&raw->raw_pktsock, pbuf, srcaddr, 0);
282*ef8d499eSDavid van Moolenbroek
283*ef8d499eSDavid van Moolenbroek return 0;
284*ef8d499eSDavid van Moolenbroek }
285*ef8d499eSDavid van Moolenbroek
286*ef8d499eSDavid van Moolenbroek /*
287*ef8d499eSDavid van Moolenbroek * Create a raw socket.
288*ef8d499eSDavid van Moolenbroek */
289*ef8d499eSDavid van Moolenbroek sockid_t
rawsock_socket(int domain,int protocol,struct sock ** sockp,const struct sockevent_ops ** ops)290*ef8d499eSDavid van Moolenbroek rawsock_socket(int domain, int protocol, struct sock ** sockp,
291*ef8d499eSDavid van Moolenbroek const struct sockevent_ops ** ops)
292*ef8d499eSDavid van Moolenbroek {
293*ef8d499eSDavid van Moolenbroek struct rawsock *raw;
294*ef8d499eSDavid van Moolenbroek unsigned int flags;
295*ef8d499eSDavid van Moolenbroek uint8_t ip_type;
296*ef8d499eSDavid van Moolenbroek
297*ef8d499eSDavid van Moolenbroek if (protocol < 0 || protocol > UINT8_MAX)
298*ef8d499eSDavid van Moolenbroek return EPROTONOSUPPORT;
299*ef8d499eSDavid van Moolenbroek
300*ef8d499eSDavid van Moolenbroek if (TAILQ_EMPTY(&raw_freelist))
301*ef8d499eSDavid van Moolenbroek return ENOBUFS;
302*ef8d499eSDavid van Moolenbroek
303*ef8d499eSDavid van Moolenbroek raw = TAILQ_FIRST(&raw_freelist);
304*ef8d499eSDavid van Moolenbroek
305*ef8d499eSDavid van Moolenbroek /*
306*ef8d499eSDavid van Moolenbroek * Initialize the structure. Do not memset it to zero, as it is still
307*ef8d499eSDavid van Moolenbroek * part of the linked free list. Initialization may still fail.
308*ef8d499eSDavid van Moolenbroek */
309*ef8d499eSDavid van Moolenbroek
310*ef8d499eSDavid van Moolenbroek ip_type = pktsock_socket(&raw->raw_pktsock, domain, RAW_SNDBUF_DEF,
311*ef8d499eSDavid van Moolenbroek RAW_RCVBUF_DEF, sockp);
312*ef8d499eSDavid van Moolenbroek
313*ef8d499eSDavid van Moolenbroek /* We should have enough PCBs so this call should not fail.. */
314*ef8d499eSDavid van Moolenbroek if ((raw->raw_pcb = raw_new_ip_type(ip_type, protocol)) == NULL)
315*ef8d499eSDavid van Moolenbroek return ENOBUFS;
316*ef8d499eSDavid van Moolenbroek raw_recv(raw->raw_pcb, rawsock_input, (void *)raw);
317*ef8d499eSDavid van Moolenbroek
318*ef8d499eSDavid van Moolenbroek /* By default, the multicast TTL is 1 and looping is enabled. */
319*ef8d499eSDavid van Moolenbroek raw_set_multicast_ttl(raw->raw_pcb, 1);
320*ef8d499eSDavid van Moolenbroek
321*ef8d499eSDavid van Moolenbroek flags = raw_flags(raw->raw_pcb);
322*ef8d499eSDavid van Moolenbroek raw_setflags(raw->raw_pcb, flags | RAW_FLAGS_MULTICAST_LOOP);
323*ef8d499eSDavid van Moolenbroek
324*ef8d499eSDavid van Moolenbroek /*
325*ef8d499eSDavid van Moolenbroek * For ICMPv6, checksum generation and verification is mandatory and
326*ef8d499eSDavid van Moolenbroek * type filtering of incoming packets is supported (RFC 3542). For all
327*ef8d499eSDavid van Moolenbroek * other IPv6 protocols, checksumming may be turned on by the user.
328*ef8d499eSDavid van Moolenbroek */
329*ef8d499eSDavid van Moolenbroek if (rawsock_is_ipv6(raw) && protocol == IPPROTO_ICMPV6) {
330*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_reqd = 1;
331*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_offset =
332*ef8d499eSDavid van Moolenbroek offsetof(struct icmp6_hdr, icmp6_cksum);
333*ef8d499eSDavid van Moolenbroek
334*ef8d499eSDavid van Moolenbroek ICMP6_FILTER_SETPASSALL(&raw->raw_icmp6filter);
335*ef8d499eSDavid van Moolenbroek } else
336*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_reqd = 0;
337*ef8d499eSDavid van Moolenbroek
338*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&raw_freelist, raw, raw_next);
339*ef8d499eSDavid van Moolenbroek
340*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&raw_activelist, raw, raw_next);
341*ef8d499eSDavid van Moolenbroek
342*ef8d499eSDavid van Moolenbroek *ops = &rawsock_ops;
343*ef8d499eSDavid van Moolenbroek return SOCKID_RAW | (sockid_t)(raw - raw_array);
344*ef8d499eSDavid van Moolenbroek }
345*ef8d499eSDavid van Moolenbroek
346*ef8d499eSDavid van Moolenbroek /*
347*ef8d499eSDavid van Moolenbroek * Bind a raw socket to a local address.
348*ef8d499eSDavid van Moolenbroek */
349*ef8d499eSDavid van Moolenbroek static int
rawsock_bind(struct sock * sock,const struct sockaddr * addr,socklen_t addr_len,endpoint_t user_endpt)350*ef8d499eSDavid van Moolenbroek rawsock_bind(struct sock * sock, const struct sockaddr * addr,
351*ef8d499eSDavid van Moolenbroek socklen_t addr_len, endpoint_t user_endpt)
352*ef8d499eSDavid van Moolenbroek {
353*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
354*ef8d499eSDavid van Moolenbroek ip_addr_t ipaddr;
355*ef8d499eSDavid van Moolenbroek err_t err;
356*ef8d499eSDavid van Moolenbroek int r;
357*ef8d499eSDavid van Moolenbroek
358*ef8d499eSDavid van Moolenbroek /*
359*ef8d499eSDavid van Moolenbroek * Raw sockets may be rebound even if that is not too useful. However,
360*ef8d499eSDavid van Moolenbroek * we do not allow (re)binding when the socket is connected, so as to
361*ef8d499eSDavid van Moolenbroek * eliminate any problems with source and destination type mismatches:
362*ef8d499eSDavid van Moolenbroek * such mismatches are detected at connect time, and rebinding would
363*ef8d499eSDavid van Moolenbroek * avoid those, possibly triggering lwIP asserts as a result.
364*ef8d499eSDavid van Moolenbroek */
365*ef8d499eSDavid van Moolenbroek if (rawsock_is_conn(raw))
366*ef8d499eSDavid van Moolenbroek return EINVAL;
367*ef8d499eSDavid van Moolenbroek
368*ef8d499eSDavid van Moolenbroek if ((r = ipsock_get_src_addr(rawsock_get_ipsock(raw), addr, addr_len,
369*ef8d499eSDavid van Moolenbroek user_endpt, &raw->raw_pcb->local_ip, 0 /*local_port*/,
370*ef8d499eSDavid van Moolenbroek TRUE /*allow_mcast*/, &ipaddr, NULL /*portp*/)) != OK)
371*ef8d499eSDavid van Moolenbroek return r;
372*ef8d499eSDavid van Moolenbroek
373*ef8d499eSDavid van Moolenbroek err = raw_bind(raw->raw_pcb, &ipaddr);
374*ef8d499eSDavid van Moolenbroek
375*ef8d499eSDavid van Moolenbroek return util_convert_err(err);
376*ef8d499eSDavid van Moolenbroek }
377*ef8d499eSDavid van Moolenbroek
378*ef8d499eSDavid van Moolenbroek /*
379*ef8d499eSDavid van Moolenbroek * Connect a raw socket to a remote address.
380*ef8d499eSDavid van Moolenbroek */
381*ef8d499eSDavid van Moolenbroek static int
rawsock_connect(struct sock * sock,const struct sockaddr * addr,socklen_t addr_len,endpoint_t user_endpt __unused)382*ef8d499eSDavid van Moolenbroek rawsock_connect(struct sock * sock, const struct sockaddr * addr,
383*ef8d499eSDavid van Moolenbroek socklen_t addr_len, endpoint_t user_endpt __unused)
384*ef8d499eSDavid van Moolenbroek {
385*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
386*ef8d499eSDavid van Moolenbroek const ip_addr_t *src_addr;
387*ef8d499eSDavid van Moolenbroek ip_addr_t dst_addr;
388*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
389*ef8d499eSDavid van Moolenbroek uint32_t ifindex, ifindex2;
390*ef8d499eSDavid van Moolenbroek err_t err;
391*ef8d499eSDavid van Moolenbroek int r;
392*ef8d499eSDavid van Moolenbroek
393*ef8d499eSDavid van Moolenbroek /*
394*ef8d499eSDavid van Moolenbroek * One may "unconnect" socket by providing an address with family
395*ef8d499eSDavid van Moolenbroek * AF_UNSPEC.
396*ef8d499eSDavid van Moolenbroek */
397*ef8d499eSDavid van Moolenbroek if (addr_is_unspec(addr, addr_len)) {
398*ef8d499eSDavid van Moolenbroek raw_disconnect(raw->raw_pcb);
399*ef8d499eSDavid van Moolenbroek
400*ef8d499eSDavid van Moolenbroek return OK;
401*ef8d499eSDavid van Moolenbroek }
402*ef8d499eSDavid van Moolenbroek
403*ef8d499eSDavid van Moolenbroek if ((r = ipsock_get_dst_addr(rawsock_get_ipsock(raw), addr, addr_len,
404*ef8d499eSDavid van Moolenbroek &raw->raw_pcb->local_ip, &dst_addr, NULL /*dst_port*/)) != OK)
405*ef8d499eSDavid van Moolenbroek return r;
406*ef8d499eSDavid van Moolenbroek
407*ef8d499eSDavid van Moolenbroek /*
408*ef8d499eSDavid van Moolenbroek * Bind explicitly to a source address if the PCB is not bound to one
409*ef8d499eSDavid van Moolenbroek * yet. This is expected in the BSD socket API, but lwIP does not do
410*ef8d499eSDavid van Moolenbroek * it for us.
411*ef8d499eSDavid van Moolenbroek */
412*ef8d499eSDavid van Moolenbroek if (ip_addr_isany(&raw->raw_pcb->local_ip)) {
413*ef8d499eSDavid van Moolenbroek /* Help the multicast case a bit, if possible. */
414*ef8d499eSDavid van Moolenbroek ifdev = NULL;
415*ef8d499eSDavid van Moolenbroek if (ip_addr_ismulticast(&dst_addr)) {
416*ef8d499eSDavid van Moolenbroek ifindex = pktsock_get_ifindex(&raw->raw_pktsock);
417*ef8d499eSDavid van Moolenbroek ifindex2 = raw_get_multicast_netif_index(raw->raw_pcb);
418*ef8d499eSDavid van Moolenbroek if (ifindex == 0)
419*ef8d499eSDavid van Moolenbroek ifindex = ifindex2;
420*ef8d499eSDavid van Moolenbroek
421*ef8d499eSDavid van Moolenbroek if (ifindex != 0) {
422*ef8d499eSDavid van Moolenbroek ifdev = ifdev_get_by_index(ifindex);
423*ef8d499eSDavid van Moolenbroek
424*ef8d499eSDavid van Moolenbroek if (ifdev == NULL)
425*ef8d499eSDavid van Moolenbroek return ENXIO;
426*ef8d499eSDavid van Moolenbroek }
427*ef8d499eSDavid van Moolenbroek }
428*ef8d499eSDavid van Moolenbroek
429*ef8d499eSDavid van Moolenbroek src_addr = ifaddr_select(&dst_addr, ifdev, NULL /*ifdevp*/);
430*ef8d499eSDavid van Moolenbroek
431*ef8d499eSDavid van Moolenbroek if (src_addr == NULL)
432*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
433*ef8d499eSDavid van Moolenbroek
434*ef8d499eSDavid van Moolenbroek err = raw_bind(raw->raw_pcb, src_addr);
435*ef8d499eSDavid van Moolenbroek
436*ef8d499eSDavid van Moolenbroek if (err != ERR_OK)
437*ef8d499eSDavid van Moolenbroek return util_convert_err(err);
438*ef8d499eSDavid van Moolenbroek }
439*ef8d499eSDavid van Moolenbroek
440*ef8d499eSDavid van Moolenbroek /*
441*ef8d499eSDavid van Moolenbroek * Connecting a raw socket serves two main purposes: 1) the socket uses
442*ef8d499eSDavid van Moolenbroek * the address as destination when sending, and 2) the socket receives
443*ef8d499eSDavid van Moolenbroek * packets from only the connected address.
444*ef8d499eSDavid van Moolenbroek */
445*ef8d499eSDavid van Moolenbroek err = raw_connect(raw->raw_pcb, &dst_addr);
446*ef8d499eSDavid van Moolenbroek
447*ef8d499eSDavid van Moolenbroek if (err != ERR_OK)
448*ef8d499eSDavid van Moolenbroek return util_convert_err(err);
449*ef8d499eSDavid van Moolenbroek
450*ef8d499eSDavid van Moolenbroek return OK;
451*ef8d499eSDavid van Moolenbroek }
452*ef8d499eSDavid van Moolenbroek
453*ef8d499eSDavid van Moolenbroek /*
454*ef8d499eSDavid van Moolenbroek * Perform preliminary checks on a send request.
455*ef8d499eSDavid van Moolenbroek */
456*ef8d499eSDavid van Moolenbroek static int
rawsock_pre_send(struct sock * sock,size_t len,socklen_t ctl_len __unused,const struct sockaddr * addr,socklen_t addr_len __unused,endpoint_t user_endpt __unused,int flags)457*ef8d499eSDavid van Moolenbroek rawsock_pre_send(struct sock * sock, size_t len, socklen_t ctl_len __unused,
458*ef8d499eSDavid van Moolenbroek const struct sockaddr * addr, socklen_t addr_len __unused,
459*ef8d499eSDavid van Moolenbroek endpoint_t user_endpt __unused, int flags)
460*ef8d499eSDavid van Moolenbroek {
461*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
462*ef8d499eSDavid van Moolenbroek
463*ef8d499eSDavid van Moolenbroek if ((flags & ~MSG_DONTROUTE) != 0)
464*ef8d499eSDavid van Moolenbroek return EOPNOTSUPP;
465*ef8d499eSDavid van Moolenbroek
466*ef8d499eSDavid van Moolenbroek if (!rawsock_is_conn(raw) && addr == NULL)
467*ef8d499eSDavid van Moolenbroek return EDESTADDRREQ;
468*ef8d499eSDavid van Moolenbroek
469*ef8d499eSDavid van Moolenbroek /*
470*ef8d499eSDavid van Moolenbroek * This is only one part of the length check. The rest is done from
471*ef8d499eSDavid van Moolenbroek * rawsock_send(), once we have more information.
472*ef8d499eSDavid van Moolenbroek */
473*ef8d499eSDavid van Moolenbroek if (len > ipsock_get_sndbuf(rawsock_get_ipsock(raw)))
474*ef8d499eSDavid van Moolenbroek return EMSGSIZE;
475*ef8d499eSDavid van Moolenbroek
476*ef8d499eSDavid van Moolenbroek return OK;
477*ef8d499eSDavid van Moolenbroek }
478*ef8d499eSDavid van Moolenbroek
479*ef8d499eSDavid van Moolenbroek /*
480*ef8d499eSDavid van Moolenbroek * Swap IP-level options between the RAW PCB and the packet options structure,
481*ef8d499eSDavid van Moolenbroek * for all options that have their flag set in the packet options structure.
482*ef8d499eSDavid van Moolenbroek * This function is called twice when sending a packet. The result is that the
483*ef8d499eSDavid van Moolenbroek * flagged options are overridden for only the packet being sent.
484*ef8d499eSDavid van Moolenbroek */
485*ef8d499eSDavid van Moolenbroek static void
rawsock_swap_opt(struct rawsock * raw,struct pktopt * pkto)486*ef8d499eSDavid van Moolenbroek rawsock_swap_opt(struct rawsock * raw, struct pktopt * pkto)
487*ef8d499eSDavid van Moolenbroek {
488*ef8d499eSDavid van Moolenbroek uint8_t tos, ttl, mcast_ttl;
489*ef8d499eSDavid van Moolenbroek
490*ef8d499eSDavid van Moolenbroek if (pkto->pkto_flags & PKTOF_TOS) {
491*ef8d499eSDavid van Moolenbroek tos = raw->raw_pcb->tos;
492*ef8d499eSDavid van Moolenbroek raw->raw_pcb->tos = pkto->pkto_tos;
493*ef8d499eSDavid van Moolenbroek pkto->pkto_tos = tos;
494*ef8d499eSDavid van Moolenbroek }
495*ef8d499eSDavid van Moolenbroek
496*ef8d499eSDavid van Moolenbroek if (pkto->pkto_flags & PKTOF_TTL) {
497*ef8d499eSDavid van Moolenbroek ttl = raw->raw_pcb->ttl;
498*ef8d499eSDavid van Moolenbroek mcast_ttl = raw_get_multicast_ttl(raw->raw_pcb);
499*ef8d499eSDavid van Moolenbroek raw->raw_pcb->ttl = pkto->pkto_ttl;
500*ef8d499eSDavid van Moolenbroek raw_set_multicast_ttl(raw->raw_pcb, pkto->pkto_ttl);
501*ef8d499eSDavid van Moolenbroek pkto->pkto_ttl = ttl;
502*ef8d499eSDavid van Moolenbroek pkto->pkto_mcast_ttl = mcast_ttl;
503*ef8d499eSDavid van Moolenbroek }
504*ef8d499eSDavid van Moolenbroek }
505*ef8d499eSDavid van Moolenbroek
506*ef8d499eSDavid van Moolenbroek /*
507*ef8d499eSDavid van Moolenbroek * We are about to send the given packet that already includes an IPv4 header,
508*ef8d499eSDavid van Moolenbroek * because the IP_HDRINCL option is enabled on a raw IPv4 socket. Prepare the
509*ef8d499eSDavid van Moolenbroek * IPv4 header for sending, by modifying a few fields in it, as expected by
510*ef8d499eSDavid van Moolenbroek * userland.
511*ef8d499eSDavid van Moolenbroek */
512*ef8d499eSDavid van Moolenbroek static int
rawsock_prepare_hdrincl(struct rawsock * raw,struct pbuf * pbuf,const ip_addr_t * src_addr)513*ef8d499eSDavid van Moolenbroek rawsock_prepare_hdrincl(struct rawsock * raw, struct pbuf * pbuf,
514*ef8d499eSDavid van Moolenbroek const ip_addr_t * src_addr)
515*ef8d499eSDavid van Moolenbroek {
516*ef8d499eSDavid van Moolenbroek struct ip_hdr *iphdr;
517*ef8d499eSDavid van Moolenbroek size_t hlen;
518*ef8d499eSDavid van Moolenbroek
519*ef8d499eSDavid van Moolenbroek /*
520*ef8d499eSDavid van Moolenbroek * lwIP obtains the destination address from the IP packet header in
521*ef8d499eSDavid van Moolenbroek * this case, so make sure the packet has a full-sized header.
522*ef8d499eSDavid van Moolenbroek */
523*ef8d499eSDavid van Moolenbroek if (pbuf->len < sizeof(struct ip_hdr))
524*ef8d499eSDavid van Moolenbroek return EINVAL;
525*ef8d499eSDavid van Moolenbroek
526*ef8d499eSDavid van Moolenbroek iphdr = (struct ip_hdr *)pbuf->payload;
527*ef8d499eSDavid van Moolenbroek
528*ef8d499eSDavid van Moolenbroek /*
529*ef8d499eSDavid van Moolenbroek * Fill in the source address if it is not set, and do the byte
530*ef8d499eSDavid van Moolenbroek * swapping and checksum computation common for the BSDs, without which
531*ef8d499eSDavid van Moolenbroek * ping(8) and traceroute(8) do not work properly. We consider this a
532*ef8d499eSDavid van Moolenbroek * convenience feature, so malformed packets are simply sent as is.
533*ef8d499eSDavid van Moolenbroek * TODO: deal with type punning..
534*ef8d499eSDavid van Moolenbroek */
535*ef8d499eSDavid van Moolenbroek hlen = (size_t)IPH_HL(iphdr) << 2;
536*ef8d499eSDavid van Moolenbroek
537*ef8d499eSDavid van Moolenbroek if (pbuf->len >= hlen) {
538*ef8d499eSDavid van Moolenbroek /* Fill in the source address if it is blank. */
539*ef8d499eSDavid van Moolenbroek if (iphdr->src.addr == PP_HTONL(INADDR_ANY)) {
540*ef8d499eSDavid van Moolenbroek assert(IP_IS_V4(src_addr));
541*ef8d499eSDavid van Moolenbroek
542*ef8d499eSDavid van Moolenbroek iphdr->src.addr = ip_addr_get_ip4_u32(src_addr);
543*ef8d499eSDavid van Moolenbroek }
544*ef8d499eSDavid van Moolenbroek
545*ef8d499eSDavid van Moolenbroek IPH_LEN(iphdr) = htons(IPH_LEN(iphdr));
546*ef8d499eSDavid van Moolenbroek IPH_OFFSET(iphdr) = htons(IPH_OFFSET(iphdr));
547*ef8d499eSDavid van Moolenbroek IPH_CHKSUM(iphdr) = 0;
548*ef8d499eSDavid van Moolenbroek
549*ef8d499eSDavid van Moolenbroek IPH_CHKSUM(iphdr) = inet_chksum(iphdr, hlen);
550*ef8d499eSDavid van Moolenbroek }
551*ef8d499eSDavid van Moolenbroek
552*ef8d499eSDavid van Moolenbroek return OK;
553*ef8d499eSDavid van Moolenbroek }
554*ef8d499eSDavid van Moolenbroek
555*ef8d499eSDavid van Moolenbroek /*
556*ef8d499eSDavid van Moolenbroek * Send a packet on a raw socket.
557*ef8d499eSDavid van Moolenbroek */
558*ef8d499eSDavid van Moolenbroek static int
rawsock_send(struct sock * sock,const struct sockdriver_data * data,size_t len,size_t * off,const struct sockdriver_data * ctl __unused,socklen_t ctl_len __unused,socklen_t * ctl_off __unused,const struct sockaddr * addr,socklen_t addr_len,endpoint_t user_endpt __unused,int flags,size_t min __unused)559*ef8d499eSDavid van Moolenbroek rawsock_send(struct sock * sock, const struct sockdriver_data * data,
560*ef8d499eSDavid van Moolenbroek size_t len, size_t * off, const struct sockdriver_data * ctl __unused,
561*ef8d499eSDavid van Moolenbroek socklen_t ctl_len __unused, socklen_t * ctl_off __unused,
562*ef8d499eSDavid van Moolenbroek const struct sockaddr * addr, socklen_t addr_len,
563*ef8d499eSDavid van Moolenbroek endpoint_t user_endpt __unused, int flags, size_t min __unused)
564*ef8d499eSDavid van Moolenbroek {
565*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
566*ef8d499eSDavid van Moolenbroek struct pktopt pktopt;
567*ef8d499eSDavid van Moolenbroek struct pbuf *pbuf;
568*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
569*ef8d499eSDavid van Moolenbroek struct netif *netif;
570*ef8d499eSDavid van Moolenbroek const ip_addr_t *dst_addrp, *src_addrp;
571*ef8d499eSDavid van Moolenbroek ip_addr_t src_addr, dst_addr; /* for storage only; not always used! */
572*ef8d499eSDavid van Moolenbroek size_t hdrlen;
573*ef8d499eSDavid van Moolenbroek uint32_t ifindex;
574*ef8d499eSDavid van Moolenbroek err_t err;
575*ef8d499eSDavid van Moolenbroek int r;
576*ef8d499eSDavid van Moolenbroek
577*ef8d499eSDavid van Moolenbroek /* Copy in and parse any packet options. */
578*ef8d499eSDavid van Moolenbroek pktopt.pkto_flags = 0;
579*ef8d499eSDavid van Moolenbroek
580*ef8d499eSDavid van Moolenbroek if ((r = pktsock_get_ctl(&raw->raw_pktsock, ctl, ctl_len,
581*ef8d499eSDavid van Moolenbroek &pktopt)) != OK)
582*ef8d499eSDavid van Moolenbroek return r;
583*ef8d499eSDavid van Moolenbroek
584*ef8d499eSDavid van Moolenbroek /*
585*ef8d499eSDavid van Moolenbroek * For a more in-depth explanation of what is going on here, see the
586*ef8d499eSDavid van Moolenbroek * udpsock module, which has largely the same code but with more
587*ef8d499eSDavid van Moolenbroek * elaborate comments.
588*ef8d499eSDavid van Moolenbroek */
589*ef8d499eSDavid van Moolenbroek
590*ef8d499eSDavid van Moolenbroek /*
591*ef8d499eSDavid van Moolenbroek * Start by checking whether the source address and/or the outgoing
592*ef8d499eSDavid van Moolenbroek * interface are overridden using sticky and/or ancillary options.
593*ef8d499eSDavid van Moolenbroek */
594*ef8d499eSDavid van Moolenbroek if ((r = pktsock_get_pktinfo(&raw->raw_pktsock, &pktopt, &ifdev,
595*ef8d499eSDavid van Moolenbroek &src_addr)) != OK)
596*ef8d499eSDavid van Moolenbroek return r;
597*ef8d499eSDavid van Moolenbroek
598*ef8d499eSDavid van Moolenbroek if (ifdev != NULL && !ip_addr_isany(&src_addr)) {
599*ef8d499eSDavid van Moolenbroek /* This is guaranteed to be a proper local unicast address. */
600*ef8d499eSDavid van Moolenbroek src_addrp = &src_addr;
601*ef8d499eSDavid van Moolenbroek } else {
602*ef8d499eSDavid van Moolenbroek src_addrp = &raw->raw_pcb->local_ip;
603*ef8d499eSDavid van Moolenbroek
604*ef8d499eSDavid van Moolenbroek /*
605*ef8d499eSDavid van Moolenbroek * If the socket is bound to a multicast address, use the
606*ef8d499eSDavid van Moolenbroek * unspecified ('any') address as source address instead. A
607*ef8d499eSDavid van Moolenbroek * real source address will then be selected further below.
608*ef8d499eSDavid van Moolenbroek */
609*ef8d499eSDavid van Moolenbroek if (ip_addr_ismulticast(src_addrp))
610*ef8d499eSDavid van Moolenbroek src_addrp = IP46_ADDR_ANY(IP_GET_TYPE(src_addrp));
611*ef8d499eSDavid van Moolenbroek }
612*ef8d499eSDavid van Moolenbroek
613*ef8d499eSDavid van Moolenbroek /*
614*ef8d499eSDavid van Moolenbroek * Determine the destination address to use. If the socket is
615*ef8d499eSDavid van Moolenbroek * connected, always ignore any address provided in the send call.
616*ef8d499eSDavid van Moolenbroek */
617*ef8d499eSDavid van Moolenbroek if (!rawsock_is_conn(raw)) {
618*ef8d499eSDavid van Moolenbroek assert(addr != NULL); /* already checked in pre_send */
619*ef8d499eSDavid van Moolenbroek
620*ef8d499eSDavid van Moolenbroek if ((r = ipsock_get_dst_addr(rawsock_get_ipsock(raw), addr,
621*ef8d499eSDavid van Moolenbroek addr_len, src_addrp, &dst_addr, NULL /*dst_port*/)) != OK)
622*ef8d499eSDavid van Moolenbroek return r;
623*ef8d499eSDavid van Moolenbroek
624*ef8d499eSDavid van Moolenbroek dst_addrp = &dst_addr;
625*ef8d499eSDavid van Moolenbroek } else
626*ef8d499eSDavid van Moolenbroek dst_addrp = &raw->raw_pcb->remote_ip;
627*ef8d499eSDavid van Moolenbroek
628*ef8d499eSDavid van Moolenbroek /*
629*ef8d499eSDavid van Moolenbroek * If the destination is a multicast address, select the outgoing
630*ef8d499eSDavid van Moolenbroek * interface based on the multicast interface index, if one is set.
631*ef8d499eSDavid van Moolenbroek * This must however *not* override an interface index already
632*ef8d499eSDavid van Moolenbroek * specified using IPV6_PKTINFO, as per RFC 3542 Sec. 6.7.
633*ef8d499eSDavid van Moolenbroek */
634*ef8d499eSDavid van Moolenbroek if (ifdev == NULL && ip_addr_ismulticast(dst_addrp)) {
635*ef8d499eSDavid van Moolenbroek ifindex = raw_get_multicast_netif_index(raw->raw_pcb);
636*ef8d499eSDavid van Moolenbroek
637*ef8d499eSDavid van Moolenbroek if (ifindex != NETIF_NO_INDEX)
638*ef8d499eSDavid van Moolenbroek ifdev = ifdev_get_by_index(ifindex); /* (may fail) */
639*ef8d499eSDavid van Moolenbroek }
640*ef8d499eSDavid van Moolenbroek
641*ef8d499eSDavid van Moolenbroek /*
642*ef8d499eSDavid van Moolenbroek * If an interface has been determined already now, the send operation
643*ef8d499eSDavid van Moolenbroek * will bypass routing. In that case, we must perform our own checks
644*ef8d499eSDavid van Moolenbroek * on address zone violations, because those will not be made anywhere
645*ef8d499eSDavid van Moolenbroek * else. Subsequent steps below will never introduce violations.
646*ef8d499eSDavid van Moolenbroek */
647*ef8d499eSDavid van Moolenbroek if (ifdev != NULL && IP_IS_V6(dst_addrp)) {
648*ef8d499eSDavid van Moolenbroek if (ifaddr_is_zone_mismatch(ip_2_ip6(dst_addrp), ifdev))
649*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
650*ef8d499eSDavid van Moolenbroek
651*ef8d499eSDavid van Moolenbroek if (IP_IS_V6(src_addrp) &&
652*ef8d499eSDavid van Moolenbroek ifaddr_is_zone_mismatch(ip_2_ip6(src_addrp), ifdev))
653*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
654*ef8d499eSDavid van Moolenbroek }
655*ef8d499eSDavid van Moolenbroek
656*ef8d499eSDavid van Moolenbroek /*
657*ef8d499eSDavid van Moolenbroek * If we do not yet have an interface at this point, perform a route
658*ef8d499eSDavid van Moolenbroek * lookup to determine the outgoing interface, unless MSG_DONTROUTE is
659*ef8d499eSDavid van Moolenbroek * set.
660*ef8d499eSDavid van Moolenbroek */
661*ef8d499eSDavid van Moolenbroek if (ifdev == NULL) {
662*ef8d499eSDavid van Moolenbroek if (!(flags & MSG_DONTROUTE)) {
663*ef8d499eSDavid van Moolenbroek /*
664*ef8d499eSDavid van Moolenbroek * ip_route() should never be called with an
665*ef8d499eSDavid van Moolenbroek * IPADDR_TYPE_ANY type address. This is a lwIP-
666*ef8d499eSDavid van Moolenbroek * internal requirement; while we override both routing
667*ef8d499eSDavid van Moolenbroek * functions, we do not deviate from it.
668*ef8d499eSDavid van Moolenbroek */
669*ef8d499eSDavid van Moolenbroek if (IP_IS_ANY_TYPE_VAL(*src_addrp))
670*ef8d499eSDavid van Moolenbroek src_addrp =
671*ef8d499eSDavid van Moolenbroek IP46_ADDR_ANY(IP_GET_TYPE(dst_addrp));
672*ef8d499eSDavid van Moolenbroek
673*ef8d499eSDavid van Moolenbroek /* Perform the route lookup. */
674*ef8d499eSDavid van Moolenbroek if ((netif = ip_route(src_addrp, dst_addrp)) == NULL)
675*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
676*ef8d499eSDavid van Moolenbroek
677*ef8d499eSDavid van Moolenbroek ifdev = netif_get_ifdev(netif);
678*ef8d499eSDavid van Moolenbroek } else {
679*ef8d499eSDavid van Moolenbroek if ((ifdev = ifaddr_map_by_subnet(dst_addrp)) == NULL)
680*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
681*ef8d499eSDavid van Moolenbroek }
682*ef8d499eSDavid van Moolenbroek }
683*ef8d499eSDavid van Moolenbroek
684*ef8d499eSDavid van Moolenbroek /*
685*ef8d499eSDavid van Moolenbroek * At this point we have an outgoing interface. If we do not have a
686*ef8d499eSDavid van Moolenbroek * source address yet, pick one now. As a sidenote, if the destination
687*ef8d499eSDavid van Moolenbroek * address is scoped but has no zone, we could also fill in the zone
688*ef8d499eSDavid van Moolenbroek * now. We let lwIP handle that instead, though.
689*ef8d499eSDavid van Moolenbroek */
690*ef8d499eSDavid van Moolenbroek assert(ifdev != NULL);
691*ef8d499eSDavid van Moolenbroek
692*ef8d499eSDavid van Moolenbroek if (ip_addr_isany(src_addrp)) {
693*ef8d499eSDavid van Moolenbroek src_addrp = ifaddr_select(dst_addrp, ifdev, NULL /*ifdevp*/);
694*ef8d499eSDavid van Moolenbroek
695*ef8d499eSDavid van Moolenbroek if (src_addrp == NULL)
696*ef8d499eSDavid van Moolenbroek return EHOSTUNREACH;
697*ef8d499eSDavid van Moolenbroek }
698*ef8d499eSDavid van Moolenbroek
699*ef8d499eSDavid van Moolenbroek /*
700*ef8d499eSDavid van Moolenbroek * Now that we know the full conditions of what we are about to send,
701*ef8d499eSDavid van Moolenbroek * check whether the packet size leaves enough room for lwIP to prepend
702*ef8d499eSDavid van Moolenbroek * headers. If so, allocate a chain of pbufs for the packet.
703*ef8d499eSDavid van Moolenbroek */
704*ef8d499eSDavid van Moolenbroek assert(len <= RAW_MAX_PAYLOAD);
705*ef8d499eSDavid van Moolenbroek
706*ef8d499eSDavid van Moolenbroek if (rawsock_is_hdrincl(raw))
707*ef8d499eSDavid van Moolenbroek hdrlen = 0;
708*ef8d499eSDavid van Moolenbroek else if (IP_IS_V6(dst_addrp))
709*ef8d499eSDavid van Moolenbroek hdrlen = IP6_HLEN;
710*ef8d499eSDavid van Moolenbroek else
711*ef8d499eSDavid van Moolenbroek hdrlen = IP_HLEN;
712*ef8d499eSDavid van Moolenbroek
713*ef8d499eSDavid van Moolenbroek if (hdrlen + len > RAW_MAX_PAYLOAD)
714*ef8d499eSDavid van Moolenbroek return EMSGSIZE;
715*ef8d499eSDavid van Moolenbroek
716*ef8d499eSDavid van Moolenbroek if ((pbuf = pchain_alloc(PBUF_IP, len)) == NULL)
717*ef8d499eSDavid van Moolenbroek return ENOBUFS;
718*ef8d499eSDavid van Moolenbroek
719*ef8d499eSDavid van Moolenbroek /* Copy in the packet data. */
720*ef8d499eSDavid van Moolenbroek if ((r = pktsock_get_data(&raw->raw_pktsock, data, len, pbuf)) != OK) {
721*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
722*ef8d499eSDavid van Moolenbroek
723*ef8d499eSDavid van Moolenbroek return r;
724*ef8d499eSDavid van Moolenbroek }
725*ef8d499eSDavid van Moolenbroek
726*ef8d499eSDavid van Moolenbroek /*
727*ef8d499eSDavid van Moolenbroek * If the user has turned on IPV6_CHECKSUM, ensure that the packet is
728*ef8d499eSDavid van Moolenbroek * not only large enough to have the checksum stored at the configured
729*ef8d499eSDavid van Moolenbroek * place, but also that the checksum fits within the first pbuf: if we
730*ef8d499eSDavid van Moolenbroek * do not test this here, an assert will trigger in lwIP later. Also
731*ef8d499eSDavid van Moolenbroek * zero out the checksum field first, because lwIP does not do that.
732*ef8d499eSDavid van Moolenbroek */
733*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->chksum_reqd) {
734*ef8d499eSDavid van Moolenbroek if (pbuf->len < raw->raw_pcb->chksum_offset +
735*ef8d499eSDavid van Moolenbroek sizeof(uint16_t)) {
736*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
737*ef8d499eSDavid van Moolenbroek
738*ef8d499eSDavid van Moolenbroek return EINVAL;
739*ef8d499eSDavid van Moolenbroek }
740*ef8d499eSDavid van Moolenbroek
741*ef8d499eSDavid van Moolenbroek memset((char *)pbuf->payload + raw->raw_pcb->chksum_offset, 0,
742*ef8d499eSDavid van Moolenbroek sizeof(uint16_t));
743*ef8d499eSDavid van Moolenbroek }
744*ef8d499eSDavid van Moolenbroek
745*ef8d499eSDavid van Moolenbroek /*
746*ef8d499eSDavid van Moolenbroek * For sockets where an IPv4 header is already included in the packet,
747*ef8d499eSDavid van Moolenbroek * we need to alter a few header fields to be compatible with BSD.
748*ef8d499eSDavid van Moolenbroek */
749*ef8d499eSDavid van Moolenbroek if (rawsock_is_hdrincl(raw) &&
750*ef8d499eSDavid van Moolenbroek (r = rawsock_prepare_hdrincl(raw, pbuf, src_addrp)) != OK) {
751*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
752*ef8d499eSDavid van Moolenbroek
753*ef8d499eSDavid van Moolenbroek return r;
754*ef8d499eSDavid van Moolenbroek }
755*ef8d499eSDavid van Moolenbroek
756*ef8d499eSDavid van Moolenbroek /* Set broadcast/multicast flags for accounting purposes. */
757*ef8d499eSDavid van Moolenbroek if (ip_addr_ismulticast(dst_addrp))
758*ef8d499eSDavid van Moolenbroek pbuf->flags |= PBUF_FLAG_LLMCAST;
759*ef8d499eSDavid van Moolenbroek else if (ip_addr_isbroadcast(dst_addrp, ifdev_get_netif(ifdev)))
760*ef8d499eSDavid van Moolenbroek pbuf->flags |= PBUF_FLAG_LLBCAST;
761*ef8d499eSDavid van Moolenbroek
762*ef8d499eSDavid van Moolenbroek /* Send the packet. */
763*ef8d499eSDavid van Moolenbroek rawsock_swap_opt(raw, &pktopt);
764*ef8d499eSDavid van Moolenbroek
765*ef8d499eSDavid van Moolenbroek assert(!ip_addr_isany(src_addrp));
766*ef8d499eSDavid van Moolenbroek assert(!ip_addr_ismulticast(src_addrp));
767*ef8d499eSDavid van Moolenbroek
768*ef8d499eSDavid van Moolenbroek err = raw_sendto_if_src(raw->raw_pcb, pbuf, dst_addrp,
769*ef8d499eSDavid van Moolenbroek ifdev_get_netif(ifdev), src_addrp);
770*ef8d499eSDavid van Moolenbroek
771*ef8d499eSDavid van Moolenbroek rawsock_swap_opt(raw, &pktopt);
772*ef8d499eSDavid van Moolenbroek
773*ef8d499eSDavid van Moolenbroek /* Free the pbuf again. */
774*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
775*ef8d499eSDavid van Moolenbroek
776*ef8d499eSDavid van Moolenbroek /*
777*ef8d499eSDavid van Moolenbroek * On success, make sure to return the size of the sent packet as well.
778*ef8d499eSDavid van Moolenbroek * As an aside: ctl_off need not be updated, as it is not returned.
779*ef8d499eSDavid van Moolenbroek */
780*ef8d499eSDavid van Moolenbroek if ((r = util_convert_err(err)) == OK)
781*ef8d499eSDavid van Moolenbroek *off = len;
782*ef8d499eSDavid van Moolenbroek return r;
783*ef8d499eSDavid van Moolenbroek }
784*ef8d499eSDavid van Moolenbroek
785*ef8d499eSDavid van Moolenbroek /*
786*ef8d499eSDavid van Moolenbroek * Update the set of flag-type socket options on a raw socket.
787*ef8d499eSDavid van Moolenbroek */
788*ef8d499eSDavid van Moolenbroek static void
rawsock_setsockmask(struct sock * sock,unsigned int mask)789*ef8d499eSDavid van Moolenbroek rawsock_setsockmask(struct sock * sock, unsigned int mask)
790*ef8d499eSDavid van Moolenbroek {
791*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
792*ef8d499eSDavid van Moolenbroek
793*ef8d499eSDavid van Moolenbroek /*
794*ef8d499eSDavid van Moolenbroek * FIXME: raw sockets are not supposed to have a broardcast check, so
795*ef8d499eSDavid van Moolenbroek * perhaps just remove this and instead always set SOF_BROADCAST?
796*ef8d499eSDavid van Moolenbroek */
797*ef8d499eSDavid van Moolenbroek if (mask & SO_BROADCAST)
798*ef8d499eSDavid van Moolenbroek ip_set_option(raw->raw_pcb, SOF_BROADCAST);
799*ef8d499eSDavid van Moolenbroek else
800*ef8d499eSDavid van Moolenbroek ip_reset_option(raw->raw_pcb, SOF_BROADCAST);
801*ef8d499eSDavid van Moolenbroek }
802*ef8d499eSDavid van Moolenbroek
803*ef8d499eSDavid van Moolenbroek /*
804*ef8d499eSDavid van Moolenbroek * Prepare a helper structure for IP-level option processing.
805*ef8d499eSDavid van Moolenbroek */
806*ef8d499eSDavid van Moolenbroek static void
rawsock_get_ipopts(struct rawsock * raw,struct ipopts * ipopts)807*ef8d499eSDavid van Moolenbroek rawsock_get_ipopts(struct rawsock * raw, struct ipopts * ipopts)
808*ef8d499eSDavid van Moolenbroek {
809*ef8d499eSDavid van Moolenbroek
810*ef8d499eSDavid van Moolenbroek ipopts->local_ip = &raw->raw_pcb->local_ip;
811*ef8d499eSDavid van Moolenbroek ipopts->remote_ip = &raw->raw_pcb->remote_ip;
812*ef8d499eSDavid van Moolenbroek ipopts->tos = &raw->raw_pcb->tos;
813*ef8d499eSDavid van Moolenbroek ipopts->ttl = &raw->raw_pcb->ttl;
814*ef8d499eSDavid van Moolenbroek ipopts->sndmin = RAW_SNDBUF_MIN;
815*ef8d499eSDavid van Moolenbroek ipopts->sndmax = RAW_SNDBUF_MAX;
816*ef8d499eSDavid van Moolenbroek ipopts->rcvmin = RAW_RCVBUF_MIN;
817*ef8d499eSDavid van Moolenbroek ipopts->rcvmax = RAW_RCVBUF_MAX;
818*ef8d499eSDavid van Moolenbroek }
819*ef8d499eSDavid van Moolenbroek
820*ef8d499eSDavid van Moolenbroek /*
821*ef8d499eSDavid van Moolenbroek * Set socket options on a raw socket.
822*ef8d499eSDavid van Moolenbroek */
823*ef8d499eSDavid van Moolenbroek static int
rawsock_setsockopt(struct sock * sock,int level,int name,const struct sockdriver_data * data,socklen_t len)824*ef8d499eSDavid van Moolenbroek rawsock_setsockopt(struct sock * sock, int level, int name,
825*ef8d499eSDavid van Moolenbroek const struct sockdriver_data * data, socklen_t len)
826*ef8d499eSDavid van Moolenbroek {
827*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
828*ef8d499eSDavid van Moolenbroek struct ipopts ipopts;
829*ef8d499eSDavid van Moolenbroek struct icmp6_filter filter;
830*ef8d499eSDavid van Moolenbroek ip_addr_t ipaddr;
831*ef8d499eSDavid van Moolenbroek struct in_addr in_addr;
832*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
833*ef8d499eSDavid van Moolenbroek unsigned int flags;
834*ef8d499eSDavid van Moolenbroek uint32_t ifindex;
835*ef8d499eSDavid van Moolenbroek uint8_t byte;
836*ef8d499eSDavid van Moolenbroek int r, val;
837*ef8d499eSDavid van Moolenbroek
838*ef8d499eSDavid van Moolenbroek /*
839*ef8d499eSDavid van Moolenbroek * Unfortunately, we have to duplicate most of the multicast options
840*ef8d499eSDavid van Moolenbroek * rather than sharing them with udpsock at the pktsock level. The
841*ef8d499eSDavid van Moolenbroek * reason is that each of the PCBs have their own multicast abstraction
842*ef8d499eSDavid van Moolenbroek * functions and so we cannot merge the rest. Same for getsockopt.
843*ef8d499eSDavid van Moolenbroek */
844*ef8d499eSDavid van Moolenbroek
845*ef8d499eSDavid van Moolenbroek switch (level) {
846*ef8d499eSDavid van Moolenbroek case IPPROTO_IP:
847*ef8d499eSDavid van Moolenbroek if (rawsock_is_ipv6(raw))
848*ef8d499eSDavid van Moolenbroek break;
849*ef8d499eSDavid van Moolenbroek
850*ef8d499eSDavid van Moolenbroek switch (name) {
851*ef8d499eSDavid van Moolenbroek case IP_HDRINCL:
852*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
853*ef8d499eSDavid van Moolenbroek len)) != OK)
854*ef8d499eSDavid van Moolenbroek return r;
855*ef8d499eSDavid van Moolenbroek
856*ef8d499eSDavid van Moolenbroek if (val) {
857*ef8d499eSDavid van Moolenbroek raw_setflags(raw->raw_pcb,
858*ef8d499eSDavid van Moolenbroek raw_flags(raw->raw_pcb) |
859*ef8d499eSDavid van Moolenbroek RAW_FLAGS_HDRINCL);
860*ef8d499eSDavid van Moolenbroek } else {
861*ef8d499eSDavid van Moolenbroek raw_setflags(raw->raw_pcb,
862*ef8d499eSDavid van Moolenbroek raw_flags(raw->raw_pcb) &
863*ef8d499eSDavid van Moolenbroek ~RAW_FLAGS_HDRINCL);
864*ef8d499eSDavid van Moolenbroek }
865*ef8d499eSDavid van Moolenbroek
866*ef8d499eSDavid van Moolenbroek return OK;
867*ef8d499eSDavid van Moolenbroek
868*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_IF:
869*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
870*ef8d499eSDavid van Moolenbroek
871*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &in_addr,
872*ef8d499eSDavid van Moolenbroek sizeof(in_addr), len)) != OK)
873*ef8d499eSDavid van Moolenbroek return r;
874*ef8d499eSDavid van Moolenbroek
875*ef8d499eSDavid van Moolenbroek ip_addr_set_ip4_u32(&ipaddr, in_addr.s_addr);
876*ef8d499eSDavid van Moolenbroek
877*ef8d499eSDavid van Moolenbroek if ((ifdev = ifaddr_map_by_addr(&ipaddr)) == NULL)
878*ef8d499eSDavid van Moolenbroek return EADDRNOTAVAIL;
879*ef8d499eSDavid van Moolenbroek
880*ef8d499eSDavid van Moolenbroek raw_set_multicast_netif_index(raw->raw_pcb,
881*ef8d499eSDavid van Moolenbroek ifdev_get_index(ifdev));
882*ef8d499eSDavid van Moolenbroek
883*ef8d499eSDavid van Moolenbroek return OK;
884*ef8d499eSDavid van Moolenbroek
885*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_LOOP:
886*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
887*ef8d499eSDavid van Moolenbroek
888*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &byte,
889*ef8d499eSDavid van Moolenbroek sizeof(byte), len)) != OK)
890*ef8d499eSDavid van Moolenbroek return r;
891*ef8d499eSDavid van Moolenbroek
892*ef8d499eSDavid van Moolenbroek flags = raw_flags(raw->raw_pcb);
893*ef8d499eSDavid van Moolenbroek
894*ef8d499eSDavid van Moolenbroek if (byte)
895*ef8d499eSDavid van Moolenbroek flags |= RAW_FLAGS_MULTICAST_LOOP;
896*ef8d499eSDavid van Moolenbroek else
897*ef8d499eSDavid van Moolenbroek flags &= ~RAW_FLAGS_MULTICAST_LOOP;
898*ef8d499eSDavid van Moolenbroek
899*ef8d499eSDavid van Moolenbroek raw_setflags(raw->raw_pcb, flags);
900*ef8d499eSDavid van Moolenbroek
901*ef8d499eSDavid van Moolenbroek return OK;
902*ef8d499eSDavid van Moolenbroek
903*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_TTL:
904*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
905*ef8d499eSDavid van Moolenbroek
906*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &byte,
907*ef8d499eSDavid van Moolenbroek sizeof(byte), len)) != OK)
908*ef8d499eSDavid van Moolenbroek return r;
909*ef8d499eSDavid van Moolenbroek
910*ef8d499eSDavid van Moolenbroek raw_set_multicast_ttl(raw->raw_pcb, byte);
911*ef8d499eSDavid van Moolenbroek
912*ef8d499eSDavid van Moolenbroek return OK;
913*ef8d499eSDavid van Moolenbroek }
914*ef8d499eSDavid van Moolenbroek
915*ef8d499eSDavid van Moolenbroek break;
916*ef8d499eSDavid van Moolenbroek
917*ef8d499eSDavid van Moolenbroek case IPPROTO_IPV6:
918*ef8d499eSDavid van Moolenbroek if (!rawsock_is_ipv6(raw))
919*ef8d499eSDavid van Moolenbroek break;
920*ef8d499eSDavid van Moolenbroek
921*ef8d499eSDavid van Moolenbroek switch (name) {
922*ef8d499eSDavid van Moolenbroek case IPV6_CHECKSUM:
923*ef8d499eSDavid van Moolenbroek /* ICMPv6 checksums are always computed. */
924*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->protocol == IPPROTO_ICMPV6)
925*ef8d499eSDavid van Moolenbroek return EINVAL;
926*ef8d499eSDavid van Moolenbroek
927*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
928*ef8d499eSDavid van Moolenbroek len)) != OK)
929*ef8d499eSDavid van Moolenbroek return r;
930*ef8d499eSDavid van Moolenbroek
931*ef8d499eSDavid van Moolenbroek if (val == -1) {
932*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_reqd = 0;
933*ef8d499eSDavid van Moolenbroek
934*ef8d499eSDavid van Moolenbroek return OK;
935*ef8d499eSDavid van Moolenbroek } else if (val >= 0 && !(val & 1)) {
936*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_reqd = 1;
937*ef8d499eSDavid van Moolenbroek raw->raw_pcb->chksum_offset = val;
938*ef8d499eSDavid van Moolenbroek
939*ef8d499eSDavid van Moolenbroek return OK;
940*ef8d499eSDavid van Moolenbroek } else
941*ef8d499eSDavid van Moolenbroek return EINVAL;
942*ef8d499eSDavid van Moolenbroek
943*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_IF:
944*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
945*ef8d499eSDavid van Moolenbroek
946*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
947*ef8d499eSDavid van Moolenbroek len)) != OK)
948*ef8d499eSDavid van Moolenbroek return r;
949*ef8d499eSDavid van Moolenbroek
950*ef8d499eSDavid van Moolenbroek if (val != 0) {
951*ef8d499eSDavid van Moolenbroek ifindex = (uint32_t)val;
952*ef8d499eSDavid van Moolenbroek
953*ef8d499eSDavid van Moolenbroek ifdev = ifdev_get_by_index(ifindex);
954*ef8d499eSDavid van Moolenbroek
955*ef8d499eSDavid van Moolenbroek if (ifdev == NULL)
956*ef8d499eSDavid van Moolenbroek return ENXIO;
957*ef8d499eSDavid van Moolenbroek } else
958*ef8d499eSDavid van Moolenbroek ifindex = NETIF_NO_INDEX;
959*ef8d499eSDavid van Moolenbroek
960*ef8d499eSDavid van Moolenbroek raw_set_multicast_netif_index(raw->raw_pcb, ifindex);
961*ef8d499eSDavid van Moolenbroek
962*ef8d499eSDavid van Moolenbroek return OK;
963*ef8d499eSDavid van Moolenbroek
964*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_LOOP:
965*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
966*ef8d499eSDavid van Moolenbroek
967*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
968*ef8d499eSDavid van Moolenbroek len)) != OK)
969*ef8d499eSDavid van Moolenbroek return r;
970*ef8d499eSDavid van Moolenbroek
971*ef8d499eSDavid van Moolenbroek if (val < 0 || val > 1)
972*ef8d499eSDavid van Moolenbroek return EINVAL;
973*ef8d499eSDavid van Moolenbroek
974*ef8d499eSDavid van Moolenbroek flags = raw_flags(raw->raw_pcb);
975*ef8d499eSDavid van Moolenbroek
976*ef8d499eSDavid van Moolenbroek if (val)
977*ef8d499eSDavid van Moolenbroek flags |= RAW_FLAGS_MULTICAST_LOOP;
978*ef8d499eSDavid van Moolenbroek else
979*ef8d499eSDavid van Moolenbroek flags &= ~RAW_FLAGS_MULTICAST_LOOP;
980*ef8d499eSDavid van Moolenbroek
981*ef8d499eSDavid van Moolenbroek /*
982*ef8d499eSDavid van Moolenbroek * lwIP's IPv6 functionality does not actually check
983*ef8d499eSDavid van Moolenbroek * this flag at all yet. We set it in the hope that
984*ef8d499eSDavid van Moolenbroek * one day this will magically start working.
985*ef8d499eSDavid van Moolenbroek */
986*ef8d499eSDavid van Moolenbroek raw_setflags(raw->raw_pcb, flags);
987*ef8d499eSDavid van Moolenbroek
988*ef8d499eSDavid van Moolenbroek return OK;
989*ef8d499eSDavid van Moolenbroek
990*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_HOPS:
991*ef8d499eSDavid van Moolenbroek pktsock_set_mcaware(&raw->raw_pktsock);
992*ef8d499eSDavid van Moolenbroek
993*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
994*ef8d499eSDavid van Moolenbroek len)) != OK)
995*ef8d499eSDavid van Moolenbroek return r;
996*ef8d499eSDavid van Moolenbroek
997*ef8d499eSDavid van Moolenbroek if (val < -1 || val > UINT8_MAX)
998*ef8d499eSDavid van Moolenbroek return EINVAL;
999*ef8d499eSDavid van Moolenbroek
1000*ef8d499eSDavid van Moolenbroek if (val == -1)
1001*ef8d499eSDavid van Moolenbroek val = 1;
1002*ef8d499eSDavid van Moolenbroek
1003*ef8d499eSDavid van Moolenbroek raw_set_multicast_ttl(raw->raw_pcb, val);
1004*ef8d499eSDavid van Moolenbroek
1005*ef8d499eSDavid van Moolenbroek return OK;
1006*ef8d499eSDavid van Moolenbroek }
1007*ef8d499eSDavid van Moolenbroek
1008*ef8d499eSDavid van Moolenbroek break;
1009*ef8d499eSDavid van Moolenbroek
1010*ef8d499eSDavid van Moolenbroek case IPPROTO_ICMPV6:
1011*ef8d499eSDavid van Moolenbroek if (!rawsock_is_ipv6(raw) ||
1012*ef8d499eSDavid van Moolenbroek raw->raw_pcb->protocol != IPPROTO_ICMPV6)
1013*ef8d499eSDavid van Moolenbroek break;
1014*ef8d499eSDavid van Moolenbroek
1015*ef8d499eSDavid van Moolenbroek switch (name) {
1016*ef8d499eSDavid van Moolenbroek case ICMP6_FILTER:
1017*ef8d499eSDavid van Moolenbroek /* Who comes up with these stupid exceptions? */
1018*ef8d499eSDavid van Moolenbroek if (len == 0) {
1019*ef8d499eSDavid van Moolenbroek ICMP6_FILTER_SETPASSALL(&raw->raw_icmp6filter);
1020*ef8d499eSDavid van Moolenbroek
1021*ef8d499eSDavid van Moolenbroek return OK;
1022*ef8d499eSDavid van Moolenbroek }
1023*ef8d499eSDavid van Moolenbroek
1024*ef8d499eSDavid van Moolenbroek if ((r = sockdriver_copyin_opt(data, &filter,
1025*ef8d499eSDavid van Moolenbroek sizeof(filter), len)) != OK)
1026*ef8d499eSDavid van Moolenbroek return r;
1027*ef8d499eSDavid van Moolenbroek
1028*ef8d499eSDavid van Moolenbroek /*
1029*ef8d499eSDavid van Moolenbroek * As always, never copy in the data into the actual
1030*ef8d499eSDavid van Moolenbroek * destination, as any copy may run into a copy fault
1031*ef8d499eSDavid van Moolenbroek * halfway through, potentially leaving the destination
1032*ef8d499eSDavid van Moolenbroek * in a half-updated and thus corrupted state.
1033*ef8d499eSDavid van Moolenbroek */
1034*ef8d499eSDavid van Moolenbroek memcpy(&raw->raw_icmp6filter, &filter, sizeof(filter));
1035*ef8d499eSDavid van Moolenbroek
1036*ef8d499eSDavid van Moolenbroek return OK;
1037*ef8d499eSDavid van Moolenbroek }
1038*ef8d499eSDavid van Moolenbroek }
1039*ef8d499eSDavid van Moolenbroek
1040*ef8d499eSDavid van Moolenbroek rawsock_get_ipopts(raw, &ipopts);
1041*ef8d499eSDavid van Moolenbroek
1042*ef8d499eSDavid van Moolenbroek return pktsock_setsockopt(&raw->raw_pktsock, level, name, data, len,
1043*ef8d499eSDavid van Moolenbroek &ipopts);
1044*ef8d499eSDavid van Moolenbroek }
1045*ef8d499eSDavid van Moolenbroek
1046*ef8d499eSDavid van Moolenbroek /*
1047*ef8d499eSDavid van Moolenbroek * Retrieve socket options on a raw socket.
1048*ef8d499eSDavid van Moolenbroek */
1049*ef8d499eSDavid van Moolenbroek static int
rawsock_getsockopt(struct sock * sock,int level,int name,const struct sockdriver_data * data,socklen_t * len)1050*ef8d499eSDavid van Moolenbroek rawsock_getsockopt(struct sock * sock, int level, int name,
1051*ef8d499eSDavid van Moolenbroek const struct sockdriver_data * data, socklen_t * len)
1052*ef8d499eSDavid van Moolenbroek {
1053*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1054*ef8d499eSDavid van Moolenbroek struct ipopts ipopts;
1055*ef8d499eSDavid van Moolenbroek const ip4_addr_t *ip4addr;
1056*ef8d499eSDavid van Moolenbroek struct in_addr in_addr;
1057*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
1058*ef8d499eSDavid van Moolenbroek unsigned int flags;
1059*ef8d499eSDavid van Moolenbroek uint32_t ifindex;
1060*ef8d499eSDavid van Moolenbroek uint8_t byte;
1061*ef8d499eSDavid van Moolenbroek int val;
1062*ef8d499eSDavid van Moolenbroek
1063*ef8d499eSDavid van Moolenbroek switch (level) {
1064*ef8d499eSDavid van Moolenbroek case IPPROTO_IP:
1065*ef8d499eSDavid van Moolenbroek if (rawsock_is_ipv6(raw))
1066*ef8d499eSDavid van Moolenbroek break;
1067*ef8d499eSDavid van Moolenbroek
1068*ef8d499eSDavid van Moolenbroek switch (name) {
1069*ef8d499eSDavid van Moolenbroek case IP_HDRINCL:
1070*ef8d499eSDavid van Moolenbroek val = !!rawsock_is_hdrincl(raw);
1071*ef8d499eSDavid van Moolenbroek
1072*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &val, sizeof(val),
1073*ef8d499eSDavid van Moolenbroek len);
1074*ef8d499eSDavid van Moolenbroek
1075*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_IF:
1076*ef8d499eSDavid van Moolenbroek ifindex = raw_get_multicast_netif_index(raw->raw_pcb);
1077*ef8d499eSDavid van Moolenbroek
1078*ef8d499eSDavid van Moolenbroek /*
1079*ef8d499eSDavid van Moolenbroek * Map back from the interface index to the IPv4
1080*ef8d499eSDavid van Moolenbroek * address assigned to the corresponding interface.
1081*ef8d499eSDavid van Moolenbroek * Should this not work out, return the 'any' address.
1082*ef8d499eSDavid van Moolenbroek */
1083*ef8d499eSDavid van Moolenbroek if (ifindex != NETIF_NO_INDEX &&
1084*ef8d499eSDavid van Moolenbroek (ifdev = ifdev_get_by_index(ifindex)) != NULL) {
1085*ef8d499eSDavid van Moolenbroek ip4addr =
1086*ef8d499eSDavid van Moolenbroek netif_ip4_addr(ifdev_get_netif(ifdev));
1087*ef8d499eSDavid van Moolenbroek
1088*ef8d499eSDavid van Moolenbroek in_addr.s_addr = ip4_addr_get_u32(ip4addr);
1089*ef8d499eSDavid van Moolenbroek } else
1090*ef8d499eSDavid van Moolenbroek in_addr.s_addr = PP_HTONL(INADDR_ANY);
1091*ef8d499eSDavid van Moolenbroek
1092*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &in_addr,
1093*ef8d499eSDavid van Moolenbroek sizeof(in_addr), len);
1094*ef8d499eSDavid van Moolenbroek
1095*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_LOOP:
1096*ef8d499eSDavid van Moolenbroek flags = raw_flags(raw->raw_pcb);
1097*ef8d499eSDavid van Moolenbroek
1098*ef8d499eSDavid van Moolenbroek byte = !!(flags & RAW_FLAGS_MULTICAST_LOOP);
1099*ef8d499eSDavid van Moolenbroek
1100*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &byte,
1101*ef8d499eSDavid van Moolenbroek sizeof(byte), len);
1102*ef8d499eSDavid van Moolenbroek
1103*ef8d499eSDavid van Moolenbroek case IP_MULTICAST_TTL:
1104*ef8d499eSDavid van Moolenbroek byte = raw_get_multicast_ttl(raw->raw_pcb);
1105*ef8d499eSDavid van Moolenbroek
1106*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &byte,
1107*ef8d499eSDavid van Moolenbroek sizeof(byte), len);
1108*ef8d499eSDavid van Moolenbroek }
1109*ef8d499eSDavid van Moolenbroek
1110*ef8d499eSDavid van Moolenbroek break;
1111*ef8d499eSDavid van Moolenbroek
1112*ef8d499eSDavid van Moolenbroek case IPPROTO_IPV6:
1113*ef8d499eSDavid van Moolenbroek if (!rawsock_is_ipv6(raw))
1114*ef8d499eSDavid van Moolenbroek break;
1115*ef8d499eSDavid van Moolenbroek
1116*ef8d499eSDavid van Moolenbroek switch (name) {
1117*ef8d499eSDavid van Moolenbroek case IPV6_CHECKSUM:
1118*ef8d499eSDavid van Moolenbroek if (raw->raw_pcb->chksum_reqd)
1119*ef8d499eSDavid van Moolenbroek val = raw->raw_pcb->chksum_offset;
1120*ef8d499eSDavid van Moolenbroek else
1121*ef8d499eSDavid van Moolenbroek val = -1;
1122*ef8d499eSDavid van Moolenbroek
1123*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &val, sizeof(val),
1124*ef8d499eSDavid van Moolenbroek len);
1125*ef8d499eSDavid van Moolenbroek
1126*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_IF:
1127*ef8d499eSDavid van Moolenbroek ifindex = raw_get_multicast_netif_index(raw->raw_pcb);
1128*ef8d499eSDavid van Moolenbroek
1129*ef8d499eSDavid van Moolenbroek val = (int)ifindex;
1130*ef8d499eSDavid van Moolenbroek
1131*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &val, sizeof(val),
1132*ef8d499eSDavid van Moolenbroek len);
1133*ef8d499eSDavid van Moolenbroek
1134*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_LOOP:
1135*ef8d499eSDavid van Moolenbroek flags = raw_flags(raw->raw_pcb);
1136*ef8d499eSDavid van Moolenbroek
1137*ef8d499eSDavid van Moolenbroek val = !!(flags & RAW_FLAGS_MULTICAST_LOOP);
1138*ef8d499eSDavid van Moolenbroek
1139*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &val, sizeof(val),
1140*ef8d499eSDavid van Moolenbroek len);
1141*ef8d499eSDavid van Moolenbroek
1142*ef8d499eSDavid van Moolenbroek case IPV6_MULTICAST_HOPS:
1143*ef8d499eSDavid van Moolenbroek val = raw_get_multicast_ttl(raw->raw_pcb);
1144*ef8d499eSDavid van Moolenbroek
1145*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data, &val, sizeof(val),
1146*ef8d499eSDavid van Moolenbroek len);
1147*ef8d499eSDavid van Moolenbroek }
1148*ef8d499eSDavid van Moolenbroek
1149*ef8d499eSDavid van Moolenbroek break;
1150*ef8d499eSDavid van Moolenbroek
1151*ef8d499eSDavid van Moolenbroek case IPPROTO_ICMPV6:
1152*ef8d499eSDavid van Moolenbroek if (!rawsock_is_ipv6(raw) ||
1153*ef8d499eSDavid van Moolenbroek raw->raw_pcb->protocol != IPPROTO_ICMPV6)
1154*ef8d499eSDavid van Moolenbroek break;
1155*ef8d499eSDavid van Moolenbroek
1156*ef8d499eSDavid van Moolenbroek switch (name) {
1157*ef8d499eSDavid van Moolenbroek case ICMP6_FILTER:
1158*ef8d499eSDavid van Moolenbroek return sockdriver_copyout_opt(data,
1159*ef8d499eSDavid van Moolenbroek &raw->raw_icmp6filter,
1160*ef8d499eSDavid van Moolenbroek sizeof(raw->raw_icmp6filter), len);
1161*ef8d499eSDavid van Moolenbroek }
1162*ef8d499eSDavid van Moolenbroek
1163*ef8d499eSDavid van Moolenbroek break;
1164*ef8d499eSDavid van Moolenbroek }
1165*ef8d499eSDavid van Moolenbroek
1166*ef8d499eSDavid van Moolenbroek rawsock_get_ipopts(raw, &ipopts);
1167*ef8d499eSDavid van Moolenbroek
1168*ef8d499eSDavid van Moolenbroek return pktsock_getsockopt(&raw->raw_pktsock, level, name, data, len,
1169*ef8d499eSDavid van Moolenbroek &ipopts);
1170*ef8d499eSDavid van Moolenbroek }
1171*ef8d499eSDavid van Moolenbroek
1172*ef8d499eSDavid van Moolenbroek /*
1173*ef8d499eSDavid van Moolenbroek * Retrieve the local socket address of a raw socket.
1174*ef8d499eSDavid van Moolenbroek */
1175*ef8d499eSDavid van Moolenbroek static int
rawsock_getsockname(struct sock * sock,struct sockaddr * addr,socklen_t * addr_len)1176*ef8d499eSDavid van Moolenbroek rawsock_getsockname(struct sock * sock, struct sockaddr * addr,
1177*ef8d499eSDavid van Moolenbroek socklen_t * addr_len)
1178*ef8d499eSDavid van Moolenbroek {
1179*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1180*ef8d499eSDavid van Moolenbroek
1181*ef8d499eSDavid van Moolenbroek ipsock_put_addr(rawsock_get_ipsock(raw), addr, addr_len,
1182*ef8d499eSDavid van Moolenbroek &raw->raw_pcb->local_ip, 0 /*port*/);
1183*ef8d499eSDavid van Moolenbroek
1184*ef8d499eSDavid van Moolenbroek return OK;
1185*ef8d499eSDavid van Moolenbroek }
1186*ef8d499eSDavid van Moolenbroek
1187*ef8d499eSDavid van Moolenbroek /*
1188*ef8d499eSDavid van Moolenbroek * Retrieve the remote socket address of a raw socket.
1189*ef8d499eSDavid van Moolenbroek */
1190*ef8d499eSDavid van Moolenbroek static int
rawsock_getpeername(struct sock * sock,struct sockaddr * addr,socklen_t * addr_len)1191*ef8d499eSDavid van Moolenbroek rawsock_getpeername(struct sock * sock, struct sockaddr * addr,
1192*ef8d499eSDavid van Moolenbroek socklen_t * addr_len)
1193*ef8d499eSDavid van Moolenbroek {
1194*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1195*ef8d499eSDavid van Moolenbroek
1196*ef8d499eSDavid van Moolenbroek if (!rawsock_is_conn(raw))
1197*ef8d499eSDavid van Moolenbroek return ENOTCONN;
1198*ef8d499eSDavid van Moolenbroek
1199*ef8d499eSDavid van Moolenbroek ipsock_put_addr(rawsock_get_ipsock(raw), addr, addr_len,
1200*ef8d499eSDavid van Moolenbroek &raw->raw_pcb->remote_ip, 0 /*port*/);
1201*ef8d499eSDavid van Moolenbroek
1202*ef8d499eSDavid van Moolenbroek return OK;
1203*ef8d499eSDavid van Moolenbroek }
1204*ef8d499eSDavid van Moolenbroek
1205*ef8d499eSDavid van Moolenbroek /*
1206*ef8d499eSDavid van Moolenbroek * Shut down a raw socket for reading and/or writing.
1207*ef8d499eSDavid van Moolenbroek */
1208*ef8d499eSDavid van Moolenbroek static int
rawsock_shutdown(struct sock * sock,unsigned int mask)1209*ef8d499eSDavid van Moolenbroek rawsock_shutdown(struct sock * sock, unsigned int mask)
1210*ef8d499eSDavid van Moolenbroek {
1211*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1212*ef8d499eSDavid van Moolenbroek
1213*ef8d499eSDavid van Moolenbroek if (mask & SFL_SHUT_RD)
1214*ef8d499eSDavid van Moolenbroek raw_recv(raw->raw_pcb, NULL, NULL);
1215*ef8d499eSDavid van Moolenbroek
1216*ef8d499eSDavid van Moolenbroek pktsock_shutdown(&raw->raw_pktsock, mask);
1217*ef8d499eSDavid van Moolenbroek
1218*ef8d499eSDavid van Moolenbroek return OK;
1219*ef8d499eSDavid van Moolenbroek }
1220*ef8d499eSDavid van Moolenbroek
1221*ef8d499eSDavid van Moolenbroek /*
1222*ef8d499eSDavid van Moolenbroek * Close a raw socket.
1223*ef8d499eSDavid van Moolenbroek */
1224*ef8d499eSDavid van Moolenbroek static int
rawsock_close(struct sock * sock,int force __unused)1225*ef8d499eSDavid van Moolenbroek rawsock_close(struct sock * sock, int force __unused)
1226*ef8d499eSDavid van Moolenbroek {
1227*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1228*ef8d499eSDavid van Moolenbroek
1229*ef8d499eSDavid van Moolenbroek raw_recv(raw->raw_pcb, NULL, NULL);
1230*ef8d499eSDavid van Moolenbroek
1231*ef8d499eSDavid van Moolenbroek raw_remove(raw->raw_pcb);
1232*ef8d499eSDavid van Moolenbroek raw->raw_pcb = NULL;
1233*ef8d499eSDavid van Moolenbroek
1234*ef8d499eSDavid van Moolenbroek pktsock_close(&raw->raw_pktsock);
1235*ef8d499eSDavid van Moolenbroek
1236*ef8d499eSDavid van Moolenbroek return OK;
1237*ef8d499eSDavid van Moolenbroek }
1238*ef8d499eSDavid van Moolenbroek
1239*ef8d499eSDavid van Moolenbroek /*
1240*ef8d499eSDavid van Moolenbroek * Free up a closed raw socket.
1241*ef8d499eSDavid van Moolenbroek */
1242*ef8d499eSDavid van Moolenbroek static void
rawsock_free(struct sock * sock)1243*ef8d499eSDavid van Moolenbroek rawsock_free(struct sock * sock)
1244*ef8d499eSDavid van Moolenbroek {
1245*ef8d499eSDavid van Moolenbroek struct rawsock *raw = (struct rawsock *)sock;
1246*ef8d499eSDavid van Moolenbroek
1247*ef8d499eSDavid van Moolenbroek assert(raw->raw_pcb == NULL);
1248*ef8d499eSDavid van Moolenbroek
1249*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&raw_activelist, raw, raw_next);
1250*ef8d499eSDavid van Moolenbroek
1251*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_HEAD(&raw_freelist, raw, raw_next);
1252*ef8d499eSDavid van Moolenbroek }
1253*ef8d499eSDavid van Moolenbroek
1254*ef8d499eSDavid van Moolenbroek /*
1255*ef8d499eSDavid van Moolenbroek * Fill the given kinfo_pcb sysctl(7) structure with information about the RAW
1256*ef8d499eSDavid van Moolenbroek * PCB identified by the given pointer.
1257*ef8d499eSDavid van Moolenbroek */
1258*ef8d499eSDavid van Moolenbroek static void
rawsock_get_info(struct kinfo_pcb * ki,const void * ptr)1259*ef8d499eSDavid van Moolenbroek rawsock_get_info(struct kinfo_pcb * ki, const void * ptr)
1260*ef8d499eSDavid van Moolenbroek {
1261*ef8d499eSDavid van Moolenbroek const struct raw_pcb *pcb = (const struct raw_pcb *)ptr;
1262*ef8d499eSDavid van Moolenbroek struct rawsock *raw;
1263*ef8d499eSDavid van Moolenbroek
1264*ef8d499eSDavid van Moolenbroek /* We iterate our own list so we can't find "strange" PCBs. */
1265*ef8d499eSDavid van Moolenbroek raw = (struct rawsock *)pcb->recv_arg;
1266*ef8d499eSDavid van Moolenbroek assert(raw >= raw_array &&
1267*ef8d499eSDavid van Moolenbroek raw < &raw_array[__arraycount(raw_array)]);
1268*ef8d499eSDavid van Moolenbroek
1269*ef8d499eSDavid van Moolenbroek ki->ki_type = SOCK_RAW;
1270*ef8d499eSDavid van Moolenbroek ki->ki_protocol = pcb->protocol;
1271*ef8d499eSDavid van Moolenbroek
1272*ef8d499eSDavid van Moolenbroek ipsock_get_info(ki, &pcb->local_ip, 0 /*local_port*/,
1273*ef8d499eSDavid van Moolenbroek &raw->raw_pcb->remote_ip, 0 /*remote_port*/);
1274*ef8d499eSDavid van Moolenbroek
1275*ef8d499eSDavid van Moolenbroek /* TODO: change this so that sockstat(1) may work one day. */
1276*ef8d499eSDavid van Moolenbroek ki->ki_sockaddr = (uint64_t)(uintptr_t)rawsock_get_sock(raw);
1277*ef8d499eSDavid van Moolenbroek
1278*ef8d499eSDavid van Moolenbroek ki->ki_rcvq = pktsock_get_recvlen(&raw->raw_pktsock);
1279*ef8d499eSDavid van Moolenbroek
1280*ef8d499eSDavid van Moolenbroek if (rawsock_is_hdrincl(raw))
1281*ef8d499eSDavid van Moolenbroek ki->ki_pflags |= INP_HDRINCL;
1282*ef8d499eSDavid van Moolenbroek }
1283*ef8d499eSDavid van Moolenbroek
1284*ef8d499eSDavid van Moolenbroek /*
1285*ef8d499eSDavid van Moolenbroek * Given either NULL or a previously returned RAW PCB pointer, return the first
1286*ef8d499eSDavid van Moolenbroek * or next RAW PCB pointer, or NULL if there are no more. lwIP does not expose
1287*ef8d499eSDavid van Moolenbroek * 'raw_pcbs', but other modules in this service may also use RAW PCBs (which
1288*ef8d499eSDavid van Moolenbroek * should then stay hidden), so we iterate through our own list instead.
1289*ef8d499eSDavid van Moolenbroek */
1290*ef8d499eSDavid van Moolenbroek static const void *
rawsock_enum(const void * last)1291*ef8d499eSDavid van Moolenbroek rawsock_enum(const void * last)
1292*ef8d499eSDavid van Moolenbroek {
1293*ef8d499eSDavid van Moolenbroek const struct raw_pcb *pcb;
1294*ef8d499eSDavid van Moolenbroek struct rawsock *raw;
1295*ef8d499eSDavid van Moolenbroek
1296*ef8d499eSDavid van Moolenbroek if (last != NULL) {
1297*ef8d499eSDavid van Moolenbroek pcb = (const struct raw_pcb *)last;
1298*ef8d499eSDavid van Moolenbroek
1299*ef8d499eSDavid van Moolenbroek raw = (struct rawsock *)pcb->recv_arg;
1300*ef8d499eSDavid van Moolenbroek assert(raw >= raw_array &&
1301*ef8d499eSDavid van Moolenbroek raw < &raw_array[__arraycount(raw_array)]);
1302*ef8d499eSDavid van Moolenbroek
1303*ef8d499eSDavid van Moolenbroek raw = TAILQ_NEXT(raw, raw_next);
1304*ef8d499eSDavid van Moolenbroek } else
1305*ef8d499eSDavid van Moolenbroek raw = TAILQ_FIRST(&raw_activelist);
1306*ef8d499eSDavid van Moolenbroek
1307*ef8d499eSDavid van Moolenbroek if (raw != NULL)
1308*ef8d499eSDavid van Moolenbroek return raw->raw_pcb;
1309*ef8d499eSDavid van Moolenbroek else
1310*ef8d499eSDavid van Moolenbroek return NULL;
1311*ef8d499eSDavid van Moolenbroek }
1312*ef8d499eSDavid van Moolenbroek
1313*ef8d499eSDavid van Moolenbroek /*
1314*ef8d499eSDavid van Moolenbroek * Obtain the list of RAW protocol control blocks, for sysctl(7).
1315*ef8d499eSDavid van Moolenbroek */
1316*ef8d499eSDavid van Moolenbroek static ssize_t
rawsock_pcblist(struct rmib_call * call,struct rmib_node * node,struct rmib_oldp * oldp,struct rmib_newp * newp __unused)1317*ef8d499eSDavid van Moolenbroek rawsock_pcblist(struct rmib_call * call, struct rmib_node * node,
1318*ef8d499eSDavid van Moolenbroek struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
1319*ef8d499eSDavid van Moolenbroek {
1320*ef8d499eSDavid van Moolenbroek
1321*ef8d499eSDavid van Moolenbroek return util_pcblist(call, oldp, rawsock_enum, rawsock_get_info);
1322*ef8d499eSDavid van Moolenbroek }
1323*ef8d499eSDavid van Moolenbroek
1324*ef8d499eSDavid van Moolenbroek static const struct sockevent_ops rawsock_ops = {
1325*ef8d499eSDavid van Moolenbroek .sop_bind = rawsock_bind,
1326*ef8d499eSDavid van Moolenbroek .sop_connect = rawsock_connect,
1327*ef8d499eSDavid van Moolenbroek .sop_pre_send = rawsock_pre_send,
1328*ef8d499eSDavid van Moolenbroek .sop_send = rawsock_send,
1329*ef8d499eSDavid van Moolenbroek .sop_pre_recv = pktsock_pre_recv,
1330*ef8d499eSDavid van Moolenbroek .sop_recv = pktsock_recv,
1331*ef8d499eSDavid van Moolenbroek .sop_test_recv = pktsock_test_recv,
1332*ef8d499eSDavid van Moolenbroek .sop_ioctl = ifconf_ioctl,
1333*ef8d499eSDavid van Moolenbroek .sop_setsockmask = rawsock_setsockmask,
1334*ef8d499eSDavid van Moolenbroek .sop_setsockopt = rawsock_setsockopt,
1335*ef8d499eSDavid van Moolenbroek .sop_getsockopt = rawsock_getsockopt,
1336*ef8d499eSDavid van Moolenbroek .sop_getsockname = rawsock_getsockname,
1337*ef8d499eSDavid van Moolenbroek .sop_getpeername = rawsock_getpeername,
1338*ef8d499eSDavid van Moolenbroek .sop_shutdown = rawsock_shutdown,
1339*ef8d499eSDavid van Moolenbroek .sop_close = rawsock_close,
1340*ef8d499eSDavid van Moolenbroek .sop_free = rawsock_free
1341*ef8d499eSDavid van Moolenbroek };
1342