This source file includes following definitions.
- in6_pcbbind
- in6_pcbsetport
- in6_pcbconnect
- in6_pcbnotify
- in6_setsockaddr
- in6_setpeeraddr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/malloc.h>
105 #include <sys/mbuf.h>
106 #include <sys/domain.h>
107 #include <sys/protosw.h>
108 #include <sys/socket.h>
109 #include <sys/socketvar.h>
110 #include <sys/errno.h>
111 #include <sys/time.h>
112 #include <sys/proc.h>
113
114 #include <net/if.h>
115 #include <net/route.h>
116
117 #include <netinet/in.h>
118 #include <netinet/in_systm.h>
119 #include <netinet/ip.h>
120 #include <netinet/in_pcb.h>
121
122 #include <netinet6/in6_var.h>
123 #include <netinet/ip6.h>
124 #include <netinet6/ip6_var.h>
125
126
127
128
129
130 #include <dev/rndvar.h>
131
132 extern struct in6_ifaddr *in6_ifaddr;
133
134
135
136
137
138 struct in6_addr zeroin6_addr;
139
140 extern int ipport_firstauto;
141 extern int ipport_lastauto;
142 extern int ipport_hifirstauto;
143 extern int ipport_hilastauto;
144
145
146
147
148
149
150 #if 0
151 u_char inet6ctlerrmap[PRC_NCMDS] = {
152 0, 0, 0, 0,
153 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
154 EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
155 EMSGSIZE, EHOSTUNREACH, 0, 0,
156 0, 0, 0, 0,
157 ENOPROTOOPT
158 };
159 #endif
160
161
162
163
164 int
165 in6_pcbbind(inp, nam)
166 struct inpcb *inp;
167 struct mbuf *nam;
168 {
169 struct socket *so = inp->inp_socket;
170
171 struct inpcbtable *head = inp->inp_table;
172 struct sockaddr_in6 *sin6;
173 struct proc *p = curproc;
174 u_short lport = 0;
175 int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT);
176 int error;
177
178
179
180
181
182 if (in6_ifaddr == 0)
183 return EADDRNOTAVAIL;
184
185 if (inp->inp_lport != 0 || !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
186 return EINVAL;
187
188 if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0 &&
189 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
190 (so->so_options & SO_ACCEPTCONN) == 0))
191 wild |= INPLOOKUP_WILDCARD;
192
193
194
195
196 if (nam) {
197 sin6 = mtod(nam, struct sockaddr_in6 *);
198 if (nam->m_len != sizeof (*sin6))
199 return EINVAL;
200
201
202
203
204
205 if (sin6->sin6_family != AF_INET6)
206 return EAFNOSUPPORT;
207
208
209 if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
210 return EINVAL;
211
212 sin6->sin6_scope_id = 0;
213
214 lport = sin6->sin6_port;
215
216
217 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
218 return EADDRNOTAVAIL;
219
220 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
221
222
223
224
225
226
227
228 if (so->so_options & SO_REUSEADDR)
229 reuseport = SO_REUSEADDR | SO_REUSEPORT;
230 } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
231 struct ifaddr *ia = NULL;
232
233 sin6->sin6_port = 0;
234
235
236
237
238
239 sin6->sin6_flowinfo = 0;
240 if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6))
241 == NULL)
242 return EADDRNOTAVAIL;
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 if (ia &&
258 ((struct in6_ifaddr *)ia)->ia6_flags &
259 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
260 return (EADDRNOTAVAIL);
261 }
262 if (lport) {
263 struct inpcb *t;
264
265
266
267
268
269
270
271
272
273
274 if (ntohs(lport) < IPPORT_RESERVED &&
275 (error = suser(p, 0)))
276 return error;
277
278 t = in_pcblookup(head,
279 (struct in_addr *)&zeroin6_addr, 0,
280 (struct in_addr *)&sin6->sin6_addr, lport,
281 wild);
282
283 if (t && (reuseport & t->inp_socket->so_options) == 0)
284 return EADDRINUSE;
285 }
286 inp->inp_laddr6 = sin6->sin6_addr;
287 }
288
289 if (lport == 0) {
290 error = in6_pcbsetport(&inp->inp_laddr6, inp, p);
291 if (error != 0)
292 return error;
293 } else {
294 inp->inp_lport = lport;
295 in_pcbrehash(inp);
296 }
297
298 return 0;
299 }
300
301 int
302 in6_pcbsetport(laddr, inp, p)
303 struct in6_addr *laddr;
304 struct inpcb *inp;
305 struct proc *p;
306 {
307 struct socket *so = inp->inp_socket;
308 struct inpcbtable *table = inp->inp_table;
309 u_int16_t first, last;
310 u_int16_t *lastport = &inp->inp_table->inpt_lastport;
311 u_int16_t lport = 0;
312 int count;
313 int wild = INPLOOKUP_IPV6;
314 int error;
315
316
317
318 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
319 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
320 (so->so_options & SO_ACCEPTCONN) == 0))
321 wild |= INPLOOKUP_WILDCARD;
322
323 if (inp->inp_flags & INP_HIGHPORT) {
324 first = ipport_hifirstauto;
325 last = ipport_hilastauto;
326 } else if (inp->inp_flags & INP_LOWPORT) {
327 if ((error = suser(p, 0)))
328 return (EACCES);
329 first = IPPORT_RESERVED-1;
330 last = 600;
331 } else {
332 first = ipport_firstauto;
333 last = ipport_lastauto;
334 }
335
336
337
338
339
340
341
342
343
344 if (first > last) {
345
346
347
348 count = first - last;
349 if (count)
350 *lastport = first - (arc4random() % count);
351
352 do {
353 if (count-- < 0)
354 return (EADDRNOTAVAIL);
355 --*lastport;
356 if (*lastport > first || *lastport < last)
357 *lastport = first;
358 lport = htons(*lastport);
359 } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
360 in_pcblookup(table, &zeroin6_addr, 0,
361 &inp->inp_laddr6, lport, wild));
362 } else {
363
364
365
366 count = last - first;
367 if (count)
368 *lastport = first + (arc4random() % count);
369
370 do {
371 if (count-- < 0)
372 return (EADDRNOTAVAIL);
373 ++*lastport;
374 if (*lastport < first || *lastport > last)
375 *lastport = first;
376 lport = htons(*lastport);
377 } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
378 in_pcblookup(table, &zeroin6_addr, 0,
379 &inp->inp_laddr6, lport, wild));
380 }
381
382 inp->inp_lport = lport;
383 in_pcbrehash(inp);
384
385 #if 0
386 inp->inp_flowinfo = 0;
387 #endif
388
389 return 0;
390 }
391
392
393
394
395
396
397
398
399
400
401
402 int
403 in6_pcbconnect(inp, nam)
404 struct inpcb *inp;
405 struct mbuf *nam;
406 {
407 struct in6_addr *in6a = NULL;
408 struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
409 struct ifnet *ifp = NULL;
410 int error = 0;
411 struct sockaddr_in6 tmp;
412
413 (void)&in6a;
414
415 if (nam->m_len != sizeof(*sin6))
416 return (EINVAL);
417 if (sin6->sin6_family != AF_INET6)
418 return (EAFNOSUPPORT);
419 if (sin6->sin6_port == 0)
420 return (EADDRNOTAVAIL);
421
422
423 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
424 return EADDRNOTAVAIL;
425
426
427 if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6))
428 return EINVAL;
429
430
431 tmp = *sin6;
432 sin6 = &tmp;
433
434
435 if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0)
436 return EINVAL;
437
438 sin6->sin6_scope_id = 0;
439
440
441
442
443
444
445
446 in6a = in6_selectsrc(sin6, inp->inp_outputopts6,
447 inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6,
448 &error);
449 if (in6a == 0) {
450 if (error == 0)
451 error = EADDRNOTAVAIL;
452 return (error);
453 }
454
455 if (inp->inp_route6.ro_rt)
456 ifp = inp->inp_route6.ro_rt->rt_ifp;
457
458 inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
459
460 if (in_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
461 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
462 inp->inp_lport, INPLOOKUP_IPV6)) {
463 return (EADDRINUSE);
464 }
465 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
466 if (inp->inp_lport == 0)
467 (void)in6_pcbbind(inp, (struct mbuf *)0);
468 inp->inp_laddr6 = *in6a;
469 }
470 inp->inp_faddr6 = sin6->sin6_addr;
471 inp->inp_fport = sin6->sin6_port;
472 inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
473 if (ip6_auto_flowlabel)
474 inp->inp_flowinfo |=
475 (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
476 in_pcbrehash(inp);
477 return (0);
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494 int
495 in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
496 struct inpcbtable *head;
497 struct sockaddr *dst, *src;
498 uint fport_arg;
499 uint lport_arg;
500 int cmd;
501 void *cmdarg;
502 void (*notify)(struct inpcb *, int);
503 {
504 struct inpcb *inp, *ninp;
505 u_short fport = fport_arg, lport = lport_arg;
506 struct sockaddr_in6 sa6_src, *sa6_dst;
507 int errno, nmatch = 0;
508 u_int32_t flowinfo;
509
510 if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
511 return (0);
512
513 sa6_dst = (struct sockaddr_in6 *)dst;
514 if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
515 return (0);
516 if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr)) {
517 #ifdef DIAGNOSTIC
518 printf("Huh? Thought in6_pcbnotify() never got "
519 "called with mapped!\n");
520 #endif
521 return (0);
522 }
523
524
525
526
527 sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
528 flowinfo = sa6_src.sin6_flowinfo;
529
530
531
532
533
534
535
536
537
538 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
539 fport = 0;
540 lport = 0;
541 sa6_src.sin6_addr = in6addr_any;
542
543 if (cmd != PRC_HOSTDEAD)
544 notify = in_rtchange;
545 }
546 errno = inet6ctlerrmap[cmd];
547
548 for (inp = CIRCLEQ_FIRST(&head->inpt_queue);
549 inp != CIRCLEQ_END(&head->inpt_queue); inp = ninp) {
550 ninp = CIRCLEQ_NEXT(inp, inp_queue);
551
552 if ((inp->inp_flags & INP_IPV6) == 0)
553 continue;
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
587 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
588 inp->inp_route.ro_rt &&
589 !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
590 struct sockaddr_in6 *dst6;
591
592 dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst;
593 if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
594 &sa6_dst->sin6_addr))
595 goto do_notify;
596 }
597
598
599
600
601
602
603
604
605
606 if (lport == 0 && fport == 0 && flowinfo &&
607 inp->inp_socket != NULL &&
608 flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
609 IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
610 goto do_notify;
611 else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
612 &sa6_dst->sin6_addr) ||
613 inp->inp_socket == 0 ||
614 (lport && inp->inp_lport != lport) ||
615 (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
616 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
617 &sa6_src.sin6_addr)) ||
618 (fport && inp->inp_fport != fport)) {
619 continue;
620 }
621 do_notify:
622 nmatch++;
623 if (notify)
624 (*notify)(inp, errno);
625 }
626 return (nmatch);
627 }
628
629
630
631
632
633 int
634 in6_setsockaddr(inp, nam)
635 struct inpcb *inp;
636 struct mbuf *nam;
637 {
638 struct sockaddr_in6 *sin6;
639
640 nam->m_len = sizeof(struct sockaddr_in6);
641 sin6 = mtod(nam,struct sockaddr_in6 *);
642
643 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
644 sin6->sin6_family = AF_INET6;
645 sin6->sin6_len = sizeof(struct sockaddr_in6);
646 sin6->sin6_port = inp->inp_lport;
647 sin6->sin6_addr = inp->inp_laddr6;
648
649 (void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL);
650
651 return 0;
652 }
653
654
655
656
657
658 int
659 in6_setpeeraddr(inp, nam)
660 struct inpcb *inp;
661 struct mbuf *nam;
662 {
663 struct sockaddr_in6 *sin6;
664
665 nam->m_len = sizeof(struct sockaddr_in6);
666 sin6 = mtod(nam,struct sockaddr_in6 *);
667
668 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
669 sin6->sin6_family = AF_INET6;
670 sin6->sin6_len = sizeof(struct sockaddr_in6);
671 sin6->sin6_port = inp->inp_fport;
672 sin6->sin6_addr = inp->inp_faddr6;
673
674 (void)in6_recoverscope(sin6, &inp->inp_faddr6, NULL);
675
676 return 0;
677 }