1/*
2 *   $Id: recv.c,v 1.11 2006/10/09 06:21:59 psavola Exp $
3 *
4 *   Authors:
5 *    Pedro Roque		<roque@di.fc.ul.pt>
6 *    Lars Fenneberg		<lf@elemental.net>
7 *
8 *   This software is Copyright 1996,1997 by the above mentioned author(s),
9 *   All Rights Reserved.
10 *
11 *   The license which is distributed with this software in the file COPYRIGHT
12 *   applies to this software. If your distribution is missing this file, you
13 *   may request it from <pekkas@netcore.fi>.
14 *
15 */
16
17#include <config.h>
18#include <includes.h>
19#include <radvd.h>
20#include <sys/ioctl.h> /* ioctl */
21
22int
23recv_rs_ra(int sock, unsigned char *msg, struct sockaddr_in6 *addr,
24                 struct in6_pktinfo **pkt_info, int *hoplimit)
25{
26	struct msghdr mhdr;
27	struct cmsghdr *cmsg;
28	struct iovec iov;
29	static unsigned char *chdr = NULL;
30	static unsigned int chdrlen = 0;
31	int len;
32	fd_set rfds;
33
34	int fd;
35
36	if( ! chdr )
37	{
38		chdrlen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
39				CMSG_SPACE(sizeof(int));
40		if ((chdr = malloc(chdrlen)) == NULL) {
41			flog(LOG_ERR, "recv_rs_ra: malloc: %s", strerror(errno));
42			return -1;
43		}
44	}
45
46	FD_ZERO( &rfds );
47	FD_SET( sock, &rfds );
48
49	if( select( sock+1, &rfds, NULL, NULL, NULL ) < 0 )
50	{
51		if (errno != EINTR)
52			flog(LOG_ERR, "select: %s", strerror(errno));
53
54		return -1;
55	}
56
57	iov.iov_len = MSG_SIZE;
58	iov.iov_base = (caddr_t) msg;
59
60	memset(&mhdr, 0, sizeof(mhdr));
61	mhdr.msg_name = (caddr_t)addr;
62	mhdr.msg_namelen = sizeof(*addr);
63	mhdr.msg_iov = &iov;
64	mhdr.msg_iovlen = 1;
65	mhdr.msg_control = (void *)chdr;
66	mhdr.msg_controllen = chdrlen;
67
68	len = recvmsg(sock, &mhdr, 0);
69
70	if (len < 0)
71	{
72		if (errno != EINTR)
73			flog(LOG_ERR, "recvmsg: %s", strerror(errno));
74
75		return len;
76	}
77
78	*hoplimit = 255;
79
80    /* shortterm workaround to get hop limit , Bob, 07/21/2009*/
81	fd = open("/dev/acos_nat_cli", O_RDWR);
82
83    if(fd)
84    {
85        /*Foxconn modify start by Hank 09/26/2012*/
86		/*Fix wrong ioctl command*/
87        ioctl(fd, _IOR(100, 174, char *), hoplimit);
88		/*Foxconn modify end by Hank 09/26/2012*/
89        close(fd);
90    }
91    /* end of shortterm workaround to get hop limit , Bob, 07/21/2009*/
92
93    for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&mhdr, cmsg))
94	{
95          if (cmsg->cmsg_level != IPPROTO_IPV6)
96          	continue;
97
98          switch(cmsg->cmsg_type)
99          {
100#ifdef IPV6_HOPLIMIT
101              case IPV6_HOPLIMIT:
102                if ((cmsg->cmsg_len == CMSG_LEN(sizeof(int))) &&
103                    (*(int *)CMSG_DATA(cmsg) >= 0) &&
104                    (*(int *)CMSG_DATA(cmsg) < 256))
105                {
106
107                  *hoplimit = *(int *)CMSG_DATA(cmsg);
108                }
109                else
110                {
111                  flog(LOG_ERR, "received a bogus IPV6_HOPLIMIT from the kernel! len=%d, data=%d",
112                  	cmsg->cmsg_len, *(int *)CMSG_DATA(cmsg));
113                  return (-1);
114                }
115                break;
116#endif /* IPV6_HOPLIMIT */
117              case IPV6_PKTINFO:
118                if ((cmsg->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) &&
119                    ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex)
120                {
121                  *pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
122                }
123                else
124                {
125                  flog(LOG_ERR, "received a bogus IPV6_PKTINFO from the kernel! len=%d, index=%d",
126                  	cmsg->cmsg_len, ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex);
127                  return (-1);
128                }
129                break;
130          }
131	}
132
133	dlog(LOG_DEBUG, 4, "recvmsg len=%d", len);
134
135	return len;
136}
137