Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Authors: |
4 | | * Pedro Roque <roque@di.fc.ul.pt> |
5 | | * Lars Fenneberg <lf@elemental.net> |
6 | | * |
7 | | * This software is Copyright 1996,1997 by the above mentioned author(s), |
8 | | * All Rights Reserved. |
9 | | * |
10 | | * The license which is distributed with this software in the file COPYRIGHT |
11 | | * applies to this software. If your distribution is missing this file, you |
12 | | * may request it from <reubenhwk@gmail.com>. |
13 | | * |
14 | | */ |
15 | | |
16 | | #include "config.h" |
17 | | #include "includes.h" |
18 | | #include "radvd.h" |
19 | | |
20 | | int recv_rs_ra(int sock, unsigned char *msg, struct sockaddr_in6 *addr, struct in6_pktinfo **pkt_info, int *hoplimit, |
21 | | unsigned char *chdr) |
22 | 0 | { |
23 | 0 | struct iovec iov; |
24 | 0 | iov.iov_len = MSG_SIZE_RECV; |
25 | 0 | iov.iov_base = (caddr_t)msg; |
26 | |
|
27 | 0 | struct msghdr mhdr; |
28 | 0 | memset(&mhdr, 0, sizeof(mhdr)); |
29 | 0 | mhdr.msg_name = (caddr_t)addr; |
30 | 0 | mhdr.msg_namelen = sizeof(*addr); |
31 | 0 | mhdr.msg_iov = &iov; |
32 | 0 | mhdr.msg_iovlen = 1; |
33 | 0 | mhdr.msg_control = (void *)chdr; |
34 | 0 | mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); |
35 | |
|
36 | 0 | int len = recvmsg(sock, &mhdr, 0); |
37 | |
|
38 | 0 | if (len < 0) { |
39 | 0 | if (errno != EINTR) |
40 | 0 | flog(LOG_ERR, "recvmsg: %s", strerror(errno)); |
41 | |
|
42 | 0 | return len; |
43 | 0 | } |
44 | | |
45 | 0 | *hoplimit = 255; |
46 | |
|
47 | 0 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mhdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { |
48 | 0 | if (cmsg->cmsg_level != IPPROTO_IPV6) |
49 | 0 | continue; |
50 | | |
51 | 0 | switch (cmsg->cmsg_type) { |
52 | 0 | #ifdef IPV6_HOPLIMIT |
53 | 0 | case IPV6_HOPLIMIT: |
54 | 0 | if ((cmsg->cmsg_len == CMSG_LEN(sizeof(int))) && (*(int *)CMSG_DATA(cmsg) >= 0) && |
55 | 0 | (*(int *)CMSG_DATA(cmsg) < 256)) { |
56 | 0 | *hoplimit = *(int *)CMSG_DATA(cmsg); |
57 | 0 | } else { |
58 | 0 | flog(LOG_ERR, "received a bogus IPV6_HOPLIMIT from the kernel! len=%d, data=%d", |
59 | 0 | (int)cmsg->cmsg_len, *(int *)CMSG_DATA(cmsg)); |
60 | 0 | return -1; |
61 | 0 | } |
62 | 0 | break; |
63 | 0 | #endif /* IPV6_HOPLIMIT */ |
64 | 0 | case IPV6_PKTINFO: |
65 | 0 | if ((cmsg->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) && |
66 | 0 | ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex) { |
67 | 0 | *pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
68 | 0 | } else { |
69 | 0 | flog(LOG_ERR, "received a bogus IPV6_PKTINFO from the kernel! len=%d, index=%d", |
70 | 0 | (int)cmsg->cmsg_len, ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex); |
71 | 0 | return -1; |
72 | 0 | } |
73 | 0 | break; |
74 | 0 | } |
75 | 0 | } |
76 | | |
77 | 0 | char if_namebuf[IF_NAMESIZE] = {""}; |
78 | 0 | char *if_name = 0; |
79 | 0 | if (pkt_info && *pkt_info) { |
80 | 0 | if_name = if_indextoname((*pkt_info)->ipi6_ifindex, if_namebuf); |
81 | 0 | } |
82 | 0 | if (!if_name) { |
83 | 0 | if_name = "unknown interface"; |
84 | 0 | } |
85 | 0 | dlog(LOG_DEBUG, 5, "%s recvmsg len=%d", if_name, len); |
86 | |
|
87 | 0 | return len; |
88 | 0 | } |