1/* $NetBSD: t_pktinfo.c,v 1.2 2013/10/19 17:45:01 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: t_pktinfo.c,v 1.2 2013/10/19 17:45:01 christos Exp $"); 33 34#include <sys/types.h> 35#include <sys/socket.h> 36#include <netinet/in.h> 37#include <arpa/inet.h> 38#include <stdlib.h> 39#include <unistd.h> 40#include <stdio.h> 41#include <string.h> 42#include <errno.h> 43 44static const char traffic[] = "foo"; 45 46#ifdef TEST 47#include <err.h> 48#define ERR(msg) err(EXIT_FAILURE, msg) 49#define ERRX(msg, a) errx(EXIT_FAILURE, msg, a) 50#define ERRX2(msg, a1, a2) errx(EXIT_FAILURE, msg, a1, a2) 51#else 52#include <atf-c.h> 53#define ERR(msg) ATF_REQUIRE_MSG(0, "%s: %s", msg, strerror(errno)) 54#define ERRX(msg, a) ATF_REQUIRE_MSG(0, msg, a) 55#define ERRX2(msg, a1, a2) ATF_REQUIRE_MSG(0, msg, a1, a2) 56#endif 57 58static int 59server(struct sockaddr_in *sin) { 60 int s, one; 61 socklen_t len = sizeof(*sin); 62 63 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 64 ERR("socket"); 65 66 memset(sin, 0, len); 67 sin->sin_family = AF_INET; 68 sin->sin_len = len; 69 sin->sin_port = 0; 70 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 71 72 if (bind(s, (const struct sockaddr *)sin, len) == -1) 73 ERR("bind"); 74 75 if (getsockname(s, (struct sockaddr *)sin, &len) == -1) 76 ERR("getsockname"); 77 78 one = 1; 79 if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)) == -1) 80 ERR("setsockopt"); 81 if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &one, sizeof(one)) == -1) 82 ERR("setsockopt"); 83 84 return s; 85} 86 87static int 88client(struct sockaddr_in *sin) { 89 int s; 90 91 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 92 ERR("socket"); 93 if (sendto(s, traffic, sizeof(traffic), 0, 94 (const struct sockaddr *)sin, sizeof(*sin)) == -1) 95 ERR("sendto"); 96 return s; 97} 98 99static void 100receive(int s) { 101 struct msghdr msg; 102 struct cmsghdr *cmsg; 103 struct iovec iov; 104 char buf[sizeof(traffic)]; 105 struct in_pktinfo *ipi; 106 char control[CMSG_SPACE(sizeof(*ipi)) * 2]; 107 108 memset(&msg, 0, sizeof(msg)); 109 msg.msg_name = NULL; 110 msg.msg_namelen = 0; 111 msg.msg_iov = &iov; 112 memset(&iov, 0, sizeof(iov)); 113 iov.iov_base = buf; 114 iov.iov_len = sizeof(buf); 115 msg.msg_iovlen = 1; 116 msg.msg_control = control; 117 msg.msg_controllen = sizeof(control); 118 msg.msg_flags = 0; 119 120 if (recvmsg(s, &msg, 0) == -1) 121 ERR("recvmsg"); 122 123 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 124 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 125 if (cmsg->cmsg_level != IPPROTO_IP) 126 ERRX("bad level %d", cmsg->cmsg_level); 127 const char *m; 128 switch (cmsg->cmsg_type) { 129 case IP_PKTINFO: 130 m = "pktinfo"; 131 break; 132 case IP_RECVPKTINFO: 133 m = "recvpktinfo"; 134 break; 135 default: 136 m = NULL; 137 ERRX("bad type %d", cmsg->cmsg_type); 138 } 139 ipi = (void *)CMSG_DATA(cmsg); 140#ifdef TEST 141 printf("%s message received on address %s at interface %d\n", 142 m, inet_ntoa(ipi->ipi_addr), ipi->ipi_ifindex); 143#else 144 __USE(m); 145 ATF_REQUIRE_MSG(ipi->ipi_addr.s_addr == htonl(INADDR_LOOPBACK), 146 "address 0x%x != 0x%x", ipi->ipi_addr.s_addr, 147 htonl(INADDR_LOOPBACK)); 148#endif 149 } 150 151 if (strcmp(traffic, buf) != 0) 152 ERRX2("Bad message '%s' != '%s'", buf, traffic); 153} 154 155static void 156doit(void) 157{ 158 struct sockaddr_in sin; 159 int s, c; 160 s = server(&sin); 161 c = client(&sin); 162 receive(s); 163 close(s); 164 close(c); 165} 166 167#ifndef TEST 168ATF_TC(pktinfo); 169ATF_TC_HEAD(pktinfo, tc) 170{ 171 172 atf_tc_set_md_var(tc, "descr", "Check that IP_PKTINFO and " 173 "IP_RECVPKTINFO work"); 174} 175 176ATF_TC_BODY(pktinfo, tc) 177{ 178 doit(); 179} 180 181ATF_TP_ADD_TCS(tp) 182{ 183 184 ATF_TP_ADD_TC(tp, pktinfo); 185 return atf_no_error(); 186} 187#else 188 189int 190main(int argc, char *argv[]) { 191 doit(); 192 return 0; 193} 194#endif 195