1 | /* $NetBSD: raw_ip.c,v 1.161 2016/09/29 12:19:47 roy Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the project nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright (c) 1982, 1986, 1988, 1993 |
34 | * The Regents of the University of California. All rights reserved. |
35 | * |
36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions |
38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. Neither the name of the University nor the names of its contributors |
45 | * may be used to endorse or promote products derived from this software |
46 | * without specific prior written permission. |
47 | * |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. |
59 | * |
60 | * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 |
61 | */ |
62 | |
63 | /* |
64 | * Raw interface to IP protocol. |
65 | */ |
66 | |
67 | #include <sys/cdefs.h> |
68 | __KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.161 2016/09/29 12:19:47 roy Exp $" ); |
69 | |
70 | #ifdef _KERNEL_OPT |
71 | #include "opt_inet.h" |
72 | #include "opt_compat_netbsd.h" |
73 | #include "opt_ipsec.h" |
74 | #include "opt_mrouting.h" |
75 | #endif |
76 | |
77 | #include <sys/param.h> |
78 | #include <sys/sysctl.h> |
79 | #include <sys/mbuf.h> |
80 | #include <sys/socket.h> |
81 | #include <sys/protosw.h> |
82 | #include <sys/socketvar.h> |
83 | #include <sys/errno.h> |
84 | #include <sys/systm.h> |
85 | #include <sys/proc.h> |
86 | #include <sys/kauth.h> |
87 | |
88 | #include <net/if.h> |
89 | |
90 | #include <netinet/in.h> |
91 | #include <netinet/in_systm.h> |
92 | #include <netinet/ip.h> |
93 | #include <netinet/ip_var.h> |
94 | #include <netinet/ip_private.h> |
95 | #include <netinet/ip_mroute.h> |
96 | #include <netinet/ip_icmp.h> |
97 | #include <netinet/in_pcb.h> |
98 | #include <netinet/in_proto.h> |
99 | #include <netinet/in_var.h> |
100 | |
101 | #ifdef IPSEC |
102 | #include <netipsec/ipsec.h> |
103 | #include <netipsec/ipsec_var.h> |
104 | #include <netipsec/ipsec_private.h> |
105 | #endif /* IPSEC */ |
106 | |
107 | #ifdef COMPAT_50 |
108 | #include <compat/sys/socket.h> |
109 | #endif |
110 | |
111 | struct inpcbtable rawcbtable; |
112 | |
113 | int rip_pcbnotify(struct inpcbtable *, struct in_addr, |
114 | struct in_addr, int, int, void (*)(struct inpcb *, int)); |
115 | static int rip_connect_pcb(struct inpcb *, struct sockaddr_in *); |
116 | static void rip_disconnect1(struct inpcb *); |
117 | |
118 | static void sysctl_net_inet_raw_setup(struct sysctllog **); |
119 | |
120 | /* |
121 | * Nominal space allocated to a raw ip socket. |
122 | */ |
123 | #define RIPSNDQ 8192 |
124 | #define RIPRCVQ 8192 |
125 | |
126 | static u_long rip_sendspace = RIPSNDQ; |
127 | static u_long rip_recvspace = RIPRCVQ; |
128 | |
129 | /* |
130 | * Raw interface to IP protocol. |
131 | */ |
132 | |
133 | /* |
134 | * Initialize raw connection block q. |
135 | */ |
136 | void |
137 | rip_init(void) |
138 | { |
139 | |
140 | sysctl_net_inet_raw_setup(NULL); |
141 | in_pcbinit(&rawcbtable, 1, 1); |
142 | } |
143 | |
144 | static void |
145 | rip_sbappendaddr(struct inpcb *last, struct ip *ip, const struct sockaddr *sa, |
146 | int hlen, struct mbuf *opts, struct mbuf *n) |
147 | { |
148 | if (last->inp_flags & INP_NOHEADER) |
149 | m_adj(n, hlen); |
150 | if (last->inp_flags & INP_CONTROLOPTS |
151 | #ifdef SO_OTIMESTAMP |
152 | || last->inp_socket->so_options & SO_OTIMESTAMP |
153 | #endif |
154 | || last->inp_socket->so_options & SO_TIMESTAMP) |
155 | ip_savecontrol(last, &opts, ip, n); |
156 | if (sbappendaddr(&last->inp_socket->so_rcv, sa, n, opts) == 0) { |
157 | /* should notify about lost packet */ |
158 | m_freem(n); |
159 | if (opts) |
160 | m_freem(opts); |
161 | } else |
162 | sorwakeup(last->inp_socket); |
163 | } |
164 | |
165 | /* |
166 | * Setup generic address and protocol structures |
167 | * for raw_input routine, then pass them along with |
168 | * mbuf chain. |
169 | */ |
170 | void |
171 | rip_input(struct mbuf *m, ...) |
172 | { |
173 | int hlen, proto; |
174 | struct ip *ip = mtod(m, struct ip *); |
175 | struct inpcb_hdr *inph; |
176 | struct inpcb *inp; |
177 | struct inpcb *last = NULL; |
178 | struct mbuf *n, *opts = NULL; |
179 | struct sockaddr_in ripsrc; |
180 | va_list ap; |
181 | |
182 | va_start(ap, m); |
183 | (void)va_arg(ap, int); /* ignore value, advance ap */ |
184 | proto = va_arg(ap, int); |
185 | va_end(ap); |
186 | |
187 | sockaddr_in_init(&ripsrc, &ip->ip_src, 0); |
188 | |
189 | /* |
190 | * XXX Compatibility: programs using raw IP expect ip_len |
191 | * XXX to have the header length subtracted, and in host order. |
192 | * XXX ip_off is also expected to be host order. |
193 | */ |
194 | hlen = ip->ip_hl << 2; |
195 | ip->ip_len = ntohs(ip->ip_len) - hlen; |
196 | NTOHS(ip->ip_off); |
197 | |
198 | TAILQ_FOREACH(inph, &rawcbtable.inpt_queue, inph_queue) { |
199 | inp = (struct inpcb *)inph; |
200 | if (inp->inp_af != AF_INET) |
201 | continue; |
202 | if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) |
203 | continue; |
204 | if (!in_nullhost(inp->inp_laddr) && |
205 | !in_hosteq(inp->inp_laddr, ip->ip_dst)) |
206 | continue; |
207 | if (!in_nullhost(inp->inp_faddr) && |
208 | !in_hosteq(inp->inp_faddr, ip->ip_src)) |
209 | continue; |
210 | if (last == NULL) |
211 | ; |
212 | #if defined(IPSEC) |
213 | /* check AH/ESP integrity. */ |
214 | else if (ipsec_used && |
215 | ipsec4_in_reject_so(m, last->inp_socket)) { |
216 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); |
217 | /* do not inject data to pcb */ |
218 | } |
219 | #endif /*IPSEC*/ |
220 | else if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) { |
221 | rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, |
222 | n); |
223 | opts = NULL; |
224 | } |
225 | last = inp; |
226 | } |
227 | #if defined(IPSEC) |
228 | /* check AH/ESP integrity. */ |
229 | if (ipsec_used && last != NULL |
230 | && ipsec4_in_reject_so(m, last->inp_socket)) { |
231 | m_freem(m); |
232 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); |
233 | IP_STATDEC(IP_STAT_DELIVERED); |
234 | /* do not inject data to pcb */ |
235 | } else |
236 | #endif /*IPSEC*/ |
237 | if (last != NULL) |
238 | rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, m); |
239 | else if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { |
240 | uint64_t *ips; |
241 | |
242 | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, |
243 | 0, 0); |
244 | ips = IP_STAT_GETREF(); |
245 | ips[IP_STAT_NOPROTO]++; |
246 | ips[IP_STAT_DELIVERED]--; |
247 | IP_STAT_PUTREF(); |
248 | } else |
249 | m_freem(m); |
250 | return; |
251 | } |
252 | |
253 | int |
254 | rip_pcbnotify(struct inpcbtable *table, |
255 | struct in_addr faddr, struct in_addr laddr, int proto, int errno, |
256 | void (*notify)(struct inpcb *, int)) |
257 | { |
258 | struct inpcb_hdr *inph, *ninph; |
259 | int nmatch; |
260 | |
261 | nmatch = 0; |
262 | TAILQ_FOREACH_SAFE(inph, &table->inpt_queue, inph_queue, ninph) { |
263 | struct inpcb *inp = (struct inpcb *)inph; |
264 | if (inp->inp_af != AF_INET) |
265 | continue; |
266 | if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) |
267 | continue; |
268 | if (in_hosteq(inp->inp_faddr, faddr) && |
269 | in_hosteq(inp->inp_laddr, laddr)) { |
270 | (*notify)(inp, errno); |
271 | nmatch++; |
272 | } |
273 | } |
274 | |
275 | return nmatch; |
276 | } |
277 | |
278 | void * |
279 | rip_ctlinput(int cmd, const struct sockaddr *sa, void *v) |
280 | { |
281 | struct ip *ip = v; |
282 | void (*notify)(struct inpcb *, int) = in_rtchange; |
283 | int errno; |
284 | |
285 | if (sa->sa_family != AF_INET || |
286 | sa->sa_len != sizeof(struct sockaddr_in)) |
287 | return NULL; |
288 | if ((unsigned)cmd >= PRC_NCMDS) |
289 | return NULL; |
290 | errno = inetctlerrmap[cmd]; |
291 | if (PRC_IS_REDIRECT(cmd)) |
292 | notify = in_rtchange, ip = 0; |
293 | else if (cmd == PRC_HOSTDEAD) |
294 | ip = 0; |
295 | else if (errno == 0) |
296 | return NULL; |
297 | if (ip) { |
298 | rip_pcbnotify(&rawcbtable, satocsin(sa)->sin_addr, |
299 | ip->ip_src, ip->ip_p, errno, notify); |
300 | |
301 | /* XXX mapped address case */ |
302 | } else |
303 | in_pcbnotifyall(&rawcbtable, satocsin(sa)->sin_addr, errno, |
304 | notify); |
305 | return NULL; |
306 | } |
307 | |
308 | /* |
309 | * Generate IP header and pass packet to ip_output. |
310 | * Tack on options user may have setup with control call. |
311 | */ |
312 | int |
313 | rip_output(struct mbuf *m, struct inpcb *inp) |
314 | { |
315 | struct ip *ip; |
316 | struct mbuf *opts; |
317 | int flags; |
318 | |
319 | flags = |
320 | (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST |
321 | | IP_RETURNMTU; |
322 | |
323 | /* |
324 | * If the user handed us a complete IP packet, use it. |
325 | * Otherwise, allocate an mbuf for a header and fill it in. |
326 | */ |
327 | if ((inp->inp_flags & INP_HDRINCL) == 0) { |
328 | if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { |
329 | m_freem(m); |
330 | return (EMSGSIZE); |
331 | } |
332 | M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); |
333 | if (!m) |
334 | return (ENOBUFS); |
335 | ip = mtod(m, struct ip *); |
336 | ip->ip_tos = 0; |
337 | ip->ip_off = htons(0); |
338 | ip->ip_p = inp->inp_ip.ip_p; |
339 | ip->ip_len = htons(m->m_pkthdr.len); |
340 | ip->ip_src = inp->inp_laddr; |
341 | ip->ip_dst = inp->inp_faddr; |
342 | ip->ip_ttl = MAXTTL; |
343 | opts = inp->inp_options; |
344 | } else { |
345 | if (m->m_pkthdr.len > IP_MAXPACKET) { |
346 | m_freem(m); |
347 | return (EMSGSIZE); |
348 | } |
349 | ip = mtod(m, struct ip *); |
350 | |
351 | /* |
352 | * If the mbuf is read-only, we need to allocate |
353 | * a new mbuf for the header, since we need to |
354 | * modify the header. |
355 | */ |
356 | if (M_READONLY(m)) { |
357 | int hlen = ip->ip_hl << 2; |
358 | |
359 | m = m_copyup(m, hlen, (max_linkhdr + 3) & ~3); |
360 | if (m == NULL) |
361 | return (ENOMEM); /* XXX */ |
362 | ip = mtod(m, struct ip *); |
363 | } |
364 | |
365 | /* XXX userland passes ip_len and ip_off in host order */ |
366 | if (m->m_pkthdr.len != ip->ip_len) { |
367 | m_freem(m); |
368 | return (EINVAL); |
369 | } |
370 | HTONS(ip->ip_len); |
371 | HTONS(ip->ip_off); |
372 | if (ip->ip_id != 0 || m->m_pkthdr.len < IP_MINFRAGSIZE) |
373 | flags |= IP_NOIPNEWID; |
374 | opts = NULL; |
375 | /* XXX prevent ip_output from overwriting header fields */ |
376 | flags |= IP_RAWOUTPUT; |
377 | IP_STATINC(IP_STAT_RAWOUT); |
378 | } |
379 | |
380 | /* |
381 | * IP output. Note: if IP_RETURNMTU flag is set, the MTU size |
382 | * will be stored in inp_errormtu. |
383 | */ |
384 | return ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, |
385 | inp->inp_socket); |
386 | } |
387 | |
388 | /* |
389 | * Raw IP socket option processing. |
390 | */ |
391 | int |
392 | rip_ctloutput(int op, struct socket *so, struct sockopt *sopt) |
393 | { |
394 | struct inpcb *inp = sotoinpcb(so); |
395 | int error = 0; |
396 | int optval; |
397 | |
398 | if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) { |
399 | if (op == PRCO_GETOPT) { |
400 | optval = (inp->inp_flags & INP_NOHEADER) ? 1 : 0; |
401 | error = sockopt_set(sopt, &optval, sizeof(optval)); |
402 | } else if (op == PRCO_SETOPT) { |
403 | error = sockopt_getint(sopt, &optval); |
404 | if (error) |
405 | goto out; |
406 | if (optval) { |
407 | inp->inp_flags &= ~INP_HDRINCL; |
408 | inp->inp_flags |= INP_NOHEADER; |
409 | } else |
410 | inp->inp_flags &= ~INP_NOHEADER; |
411 | } |
412 | goto out; |
413 | } else if (sopt->sopt_level != IPPROTO_IP) |
414 | return ip_ctloutput(op, so, sopt); |
415 | |
416 | switch (op) { |
417 | |
418 | case PRCO_SETOPT: |
419 | switch (sopt->sopt_name) { |
420 | case IP_HDRINCL: |
421 | error = sockopt_getint(sopt, &optval); |
422 | if (error) |
423 | break; |
424 | if (optval) |
425 | inp->inp_flags |= INP_HDRINCL; |
426 | else |
427 | inp->inp_flags &= ~INP_HDRINCL; |
428 | break; |
429 | |
430 | #ifdef MROUTING |
431 | case MRT_INIT: |
432 | case MRT_DONE: |
433 | case MRT_ADD_VIF: |
434 | case MRT_DEL_VIF: |
435 | case MRT_ADD_MFC: |
436 | case MRT_DEL_MFC: |
437 | case MRT_ASSERT: |
438 | case MRT_API_CONFIG: |
439 | case MRT_ADD_BW_UPCALL: |
440 | case MRT_DEL_BW_UPCALL: |
441 | error = ip_mrouter_set(so, sopt); |
442 | break; |
443 | #endif |
444 | |
445 | default: |
446 | error = ip_ctloutput(op, so, sopt); |
447 | break; |
448 | } |
449 | break; |
450 | |
451 | case PRCO_GETOPT: |
452 | switch (sopt->sopt_name) { |
453 | case IP_HDRINCL: |
454 | optval = inp->inp_flags & INP_HDRINCL; |
455 | error = sockopt_set(sopt, &optval, sizeof(optval)); |
456 | break; |
457 | |
458 | #ifdef MROUTING |
459 | case MRT_VERSION: |
460 | case MRT_ASSERT: |
461 | case MRT_API_SUPPORT: |
462 | case MRT_API_CONFIG: |
463 | error = ip_mrouter_get(so, sopt); |
464 | break; |
465 | #endif |
466 | |
467 | default: |
468 | error = ip_ctloutput(op, so, sopt); |
469 | break; |
470 | } |
471 | break; |
472 | } |
473 | out: |
474 | return error; |
475 | } |
476 | |
477 | int |
478 | rip_connect_pcb(struct inpcb *inp, struct sockaddr_in *addr) |
479 | { |
480 | |
481 | if (IFNET_READER_EMPTY()) |
482 | return (EADDRNOTAVAIL); |
483 | if (addr->sin_family != AF_INET) |
484 | return (EAFNOSUPPORT); |
485 | inp->inp_faddr = addr->sin_addr; |
486 | return (0); |
487 | } |
488 | |
489 | static void |
490 | rip_disconnect1(struct inpcb *inp) |
491 | { |
492 | |
493 | inp->inp_faddr = zeroin_addr; |
494 | } |
495 | |
496 | static int |
497 | rip_attach(struct socket *so, int proto) |
498 | { |
499 | struct inpcb *inp; |
500 | int error; |
501 | |
502 | KASSERT(sotoinpcb(so) == NULL); |
503 | sosetlock(so); |
504 | |
505 | if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { |
506 | error = soreserve(so, rip_sendspace, rip_recvspace); |
507 | if (error) { |
508 | return error; |
509 | } |
510 | } |
511 | |
512 | error = in_pcballoc(so, &rawcbtable); |
513 | if (error) { |
514 | return error; |
515 | } |
516 | inp = sotoinpcb(so); |
517 | inp->inp_ip.ip_p = proto; |
518 | KASSERT(solocked(so)); |
519 | |
520 | return 0; |
521 | } |
522 | |
523 | static void |
524 | rip_detach(struct socket *so) |
525 | { |
526 | struct inpcb *inp; |
527 | |
528 | KASSERT(solocked(so)); |
529 | inp = sotoinpcb(so); |
530 | KASSERT(inp != NULL); |
531 | |
532 | #ifdef MROUTING |
533 | extern struct socket *ip_mrouter; |
534 | if (so == ip_mrouter) { |
535 | ip_mrouter_done(); |
536 | } |
537 | #endif |
538 | in_pcbdetach(inp); |
539 | } |
540 | |
541 | static int |
542 | rip_accept(struct socket *so, struct sockaddr *nam) |
543 | { |
544 | KASSERT(solocked(so)); |
545 | |
546 | panic("rip_accept" ); |
547 | |
548 | return EOPNOTSUPP; |
549 | } |
550 | |
551 | static int |
552 | rip_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) |
553 | { |
554 | struct inpcb *inp = sotoinpcb(so); |
555 | struct sockaddr_in *addr = (struct sockaddr_in *)nam; |
556 | int error = 0; |
557 | int s, ss; |
558 | struct ifaddr *ifa; |
559 | |
560 | KASSERT(solocked(so)); |
561 | KASSERT(inp != NULL); |
562 | KASSERT(nam != NULL); |
563 | |
564 | if (addr->sin_len != sizeof(*addr)) |
565 | return EINVAL; |
566 | |
567 | s = splsoftnet(); |
568 | if (IFNET_READER_EMPTY()) { |
569 | error = EADDRNOTAVAIL; |
570 | goto release; |
571 | } |
572 | if (addr->sin_family != AF_INET) { |
573 | error = EAFNOSUPPORT; |
574 | goto release; |
575 | } |
576 | ss = pserialize_read_enter(); |
577 | if ((ifa = ifa_ifwithaddr(sintosa(addr))) == NULL && |
578 | !in_nullhost(addr->sin_addr)) |
579 | { |
580 | pserialize_read_exit(ss); |
581 | error = EADDRNOTAVAIL; |
582 | goto release; |
583 | } |
584 | if (ifa && (ifatoia(ifa))->ia4_flags & IN6_IFF_DUPLICATED) { |
585 | pserialize_read_exit(ss); |
586 | error = EADDRNOTAVAIL; |
587 | goto release; |
588 | } |
589 | pserialize_read_exit(ss); |
590 | |
591 | inp->inp_laddr = addr->sin_addr; |
592 | |
593 | release: |
594 | splx(s); |
595 | return error; |
596 | } |
597 | |
598 | static int |
599 | rip_listen(struct socket *so, struct lwp *l) |
600 | { |
601 | KASSERT(solocked(so)); |
602 | |
603 | return EOPNOTSUPP; |
604 | } |
605 | |
606 | static int |
607 | rip_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) |
608 | { |
609 | struct inpcb *inp = sotoinpcb(so); |
610 | int error = 0; |
611 | int s; |
612 | |
613 | KASSERT(solocked(so)); |
614 | KASSERT(inp != NULL); |
615 | KASSERT(nam != NULL); |
616 | |
617 | s = splsoftnet(); |
618 | error = rip_connect_pcb(inp, (struct sockaddr_in *)nam); |
619 | if (! error) |
620 | soisconnected(so); |
621 | splx(s); |
622 | |
623 | return error; |
624 | } |
625 | |
626 | static int |
627 | rip_connect2(struct socket *so, struct socket *so2) |
628 | { |
629 | KASSERT(solocked(so)); |
630 | |
631 | return EOPNOTSUPP; |
632 | } |
633 | |
634 | static int |
635 | rip_disconnect(struct socket *so) |
636 | { |
637 | struct inpcb *inp = sotoinpcb(so); |
638 | int s; |
639 | |
640 | KASSERT(solocked(so)); |
641 | KASSERT(inp != NULL); |
642 | |
643 | s = splsoftnet(); |
644 | soisdisconnected(so); |
645 | rip_disconnect1(inp); |
646 | splx(s); |
647 | |
648 | return 0; |
649 | } |
650 | |
651 | static int |
652 | rip_shutdown(struct socket *so) |
653 | { |
654 | int s; |
655 | |
656 | KASSERT(solocked(so)); |
657 | |
658 | /* |
659 | * Mark the connection as being incapable of further input. |
660 | */ |
661 | s = splsoftnet(); |
662 | socantsendmore(so); |
663 | splx(s); |
664 | |
665 | return 0; |
666 | } |
667 | |
668 | static int |
669 | rip_abort(struct socket *so) |
670 | { |
671 | KASSERT(solocked(so)); |
672 | |
673 | panic("rip_abort" ); |
674 | |
675 | return EOPNOTSUPP; |
676 | } |
677 | |
678 | static int |
679 | rip_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) |
680 | { |
681 | return in_control(so, cmd, nam, ifp); |
682 | } |
683 | |
684 | static int |
685 | rip_stat(struct socket *so, struct stat *ub) |
686 | { |
687 | KASSERT(solocked(so)); |
688 | |
689 | /* stat: don't bother with a blocksize. */ |
690 | return 0; |
691 | } |
692 | |
693 | static int |
694 | rip_peeraddr(struct socket *so, struct sockaddr *nam) |
695 | { |
696 | int s; |
697 | |
698 | KASSERT(solocked(so)); |
699 | KASSERT(sotoinpcb(so) != NULL); |
700 | KASSERT(nam != NULL); |
701 | |
702 | s = splsoftnet(); |
703 | in_setpeeraddr(sotoinpcb(so), (struct sockaddr_in *)nam); |
704 | splx(s); |
705 | |
706 | return 0; |
707 | } |
708 | |
709 | static int |
710 | rip_sockaddr(struct socket *so, struct sockaddr *nam) |
711 | { |
712 | int s; |
713 | |
714 | KASSERT(solocked(so)); |
715 | KASSERT(sotoinpcb(so) != NULL); |
716 | KASSERT(nam != NULL); |
717 | |
718 | s = splsoftnet(); |
719 | in_setsockaddr(sotoinpcb(so), (struct sockaddr_in *)nam); |
720 | splx(s); |
721 | |
722 | return 0; |
723 | } |
724 | |
725 | static int |
726 | rip_rcvd(struct socket *so, int flags, struct lwp *l) |
727 | { |
728 | KASSERT(solocked(so)); |
729 | |
730 | return EOPNOTSUPP; |
731 | } |
732 | |
733 | static int |
734 | rip_recvoob(struct socket *so, struct mbuf *m, int flags) |
735 | { |
736 | KASSERT(solocked(so)); |
737 | |
738 | return EOPNOTSUPP; |
739 | } |
740 | |
741 | static int |
742 | rip_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, |
743 | struct mbuf *control, struct lwp *l) |
744 | { |
745 | struct inpcb *inp = sotoinpcb(so); |
746 | int error = 0; |
747 | int s; |
748 | |
749 | KASSERT(solocked(so)); |
750 | KASSERT(inp != NULL); |
751 | KASSERT(m != NULL); |
752 | |
753 | /* |
754 | * Ship a packet out. The appropriate raw output |
755 | * routine handles any massaging necessary. |
756 | */ |
757 | if (control && control->m_len) { |
758 | m_freem(control); |
759 | m_freem(m); |
760 | return EINVAL; |
761 | } |
762 | |
763 | s = splsoftnet(); |
764 | if (nam) { |
765 | if ((so->so_state & SS_ISCONNECTED) != 0) { |
766 | error = EISCONN; |
767 | goto die; |
768 | } |
769 | error = rip_connect_pcb(inp, (struct sockaddr_in *)nam); |
770 | if (error) { |
771 | die: |
772 | m_freem(m); |
773 | splx(s); |
774 | return error; |
775 | } |
776 | } else { |
777 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
778 | error = ENOTCONN; |
779 | goto die; |
780 | } |
781 | } |
782 | error = rip_output(m, inp); |
783 | if (nam) |
784 | rip_disconnect1(inp); |
785 | |
786 | splx(s); |
787 | return error; |
788 | } |
789 | |
790 | static int |
791 | rip_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) |
792 | { |
793 | KASSERT(solocked(so)); |
794 | |
795 | m_freem(m); |
796 | m_freem(control); |
797 | |
798 | return EOPNOTSUPP; |
799 | } |
800 | |
801 | static int |
802 | rip_purgeif(struct socket *so, struct ifnet *ifp) |
803 | { |
804 | int s; |
805 | |
806 | s = splsoftnet(); |
807 | mutex_enter(softnet_lock); |
808 | in_pcbpurgeif0(&rawcbtable, ifp); |
809 | in_purgeif(ifp); |
810 | in_pcbpurgeif(&rawcbtable, ifp); |
811 | mutex_exit(softnet_lock); |
812 | splx(s); |
813 | |
814 | return 0; |
815 | } |
816 | |
817 | PR_WRAP_USRREQS(rip) |
818 | #define rip_attach rip_attach_wrapper |
819 | #define rip_detach rip_detach_wrapper |
820 | #define rip_accept rip_accept_wrapper |
821 | #define rip_bind rip_bind_wrapper |
822 | #define rip_listen rip_listen_wrapper |
823 | #define rip_connect rip_connect_wrapper |
824 | #define rip_connect2 rip_connect2_wrapper |
825 | #define rip_disconnect rip_disconnect_wrapper |
826 | #define rip_shutdown rip_shutdown_wrapper |
827 | #define rip_abort rip_abort_wrapper |
828 | #define rip_ioctl rip_ioctl_wrapper |
829 | #define rip_stat rip_stat_wrapper |
830 | #define rip_peeraddr rip_peeraddr_wrapper |
831 | #define rip_sockaddr rip_sockaddr_wrapper |
832 | #define rip_rcvd rip_rcvd_wrapper |
833 | #define rip_recvoob rip_recvoob_wrapper |
834 | #define rip_send rip_send_wrapper |
835 | #define rip_sendoob rip_sendoob_wrapper |
836 | #define rip_purgeif rip_purgeif_wrapper |
837 | |
838 | const struct pr_usrreqs rip_usrreqs = { |
839 | .pr_attach = rip_attach, |
840 | .pr_detach = rip_detach, |
841 | .pr_accept = rip_accept, |
842 | .pr_bind = rip_bind, |
843 | .pr_listen = rip_listen, |
844 | .pr_connect = rip_connect, |
845 | .pr_connect2 = rip_connect2, |
846 | .pr_disconnect = rip_disconnect, |
847 | .pr_shutdown = rip_shutdown, |
848 | .pr_abort = rip_abort, |
849 | .pr_ioctl = rip_ioctl, |
850 | .pr_stat = rip_stat, |
851 | .pr_peeraddr = rip_peeraddr, |
852 | .pr_sockaddr = rip_sockaddr, |
853 | .pr_rcvd = rip_rcvd, |
854 | .pr_recvoob = rip_recvoob, |
855 | .pr_send = rip_send, |
856 | .pr_sendoob = rip_sendoob, |
857 | .pr_purgeif = rip_purgeif, |
858 | }; |
859 | |
860 | static void |
861 | sysctl_net_inet_raw_setup(struct sysctllog **clog) |
862 | { |
863 | |
864 | sysctl_createv(clog, 0, NULL, NULL, |
865 | CTLFLAG_PERMANENT, |
866 | CTLTYPE_NODE, "inet" , NULL, |
867 | NULL, 0, NULL, 0, |
868 | CTL_NET, PF_INET, CTL_EOL); |
869 | sysctl_createv(clog, 0, NULL, NULL, |
870 | CTLFLAG_PERMANENT, |
871 | CTLTYPE_NODE, "raw" , |
872 | SYSCTL_DESCR("Raw IPv4 settings" ), |
873 | NULL, 0, NULL, 0, |
874 | CTL_NET, PF_INET, IPPROTO_RAW, CTL_EOL); |
875 | |
876 | sysctl_createv(clog, 0, NULL, NULL, |
877 | CTLFLAG_PERMANENT, |
878 | CTLTYPE_STRUCT, "pcblist" , |
879 | SYSCTL_DESCR("Raw IPv4 control block list" ), |
880 | sysctl_inpcblist, 0, &rawcbtable, 0, |
881 | CTL_NET, PF_INET, IPPROTO_RAW, |
882 | CTL_CREATE, CTL_EOL); |
883 | } |
884 | |