1 /* 2 * Copyright (c) 2012 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Sepherosa Ziehau <sepherosa@gmail.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/ioctl.h> 37 #include <sys/stat.h> 38 #include <sys/socket.h> 39 40 #include <arpa/inet.h> 41 #include <netinet/in.h> 42 #include <net/if.h> 43 #include <net/if_dl.h> 44 #include <net/ethernet.h> 45 46 #include <err.h> 47 #include <fcntl.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "pktgen/pktgen.h" 54 55 #define PKTGEN_DEVPATH "/dev/pktg0" 56 57 #define DEFAULT_PORT 3000 58 59 #define INDST_MASK 0x0001 60 #define INSRC_MASK 0x0002 61 #define EADDR_MASK 0x0004 62 #define IFACE_MASK 0x0008 63 64 #define MASK_NEEDED (INDST_MASK | INSRC_MASK | EADDR_MASK | IFACE_MASK) 65 66 static void 67 usage(void) 68 { 69 fprintf(stderr, "pktgenctl " 70 "-d dst_inaddr[:dst_port] [-d dst_inaddr[:dst_port] ...] " 71 "-s src_inaddr[:src_port] " 72 "-e (gw_eaddr|dst_eaddr) -i iface " 73 "[-m data_len] [-l duration] [-D dev] [-q pktenq] [-M]\n"); 74 exit(1); 75 } 76 77 static int 78 get_port(char *str) 79 { 80 char *p; 81 82 p = strchr(str, ':'); 83 if (p == NULL) { 84 return DEFAULT_PORT; 85 } else { 86 *p = '\0'; 87 ++p; 88 return atoi(p); 89 } 90 } 91 92 int 93 main(int argc, char *argv[]) 94 { 95 struct pktgen_conf conf; 96 struct sockaddr *sa; 97 struct sockaddr_in *src_sin, *dst_sin; 98 struct sockaddr_dl sdl; 99 char eaddr_str[32]; 100 uint32_t arg_mask = 0; 101 int fd, c, n, ndst_alloc; 102 const char *dev; 103 u_long start = PKTGENSTART; 104 105 dev = PKTGEN_DEVPATH; 106 107 memset(&conf, 0, sizeof(conf)); 108 109 conf.pc_duration = 10; 110 conf.pc_datalen = 18; 111 112 sa = &conf.pc_dst_lladdr; 113 sa->sa_family = AF_LINK; 114 sa->sa_len = ETHER_ADDR_LEN; 115 116 src_sin = &conf.pc_src; 117 src_sin->sin_family = AF_INET; 118 119 ndst_alloc = 1; 120 conf.pc_dst = calloc(ndst_alloc, sizeof(struct sockaddr_in)); 121 if (conf.pc_dst == NULL) 122 err(1, "calloc(%d dst)", ndst_alloc); 123 124 conf.pc_ndst = 0; 125 while ((c = getopt(argc, argv, "d:s:e:i:m:l:D:q:M")) != -1) { 126 switch (c) { 127 case 'd': 128 if (conf.pc_ndst >= ndst_alloc) { 129 void *old = conf.pc_dst; 130 int old_ndst_alloc = ndst_alloc; 131 132 ndst_alloc *= 2; 133 conf.pc_dst = calloc(ndst_alloc, 134 sizeof(struct sockaddr_in)); 135 if (conf.pc_dst == NULL) 136 err(1, "calloc(%d dst)", ndst_alloc); 137 memcpy(conf.pc_dst, old, 138 old_ndst_alloc * sizeof(struct sockaddr_in)); 139 free(old); 140 } 141 dst_sin = &conf.pc_dst[conf.pc_ndst++]; 142 143 dst_sin->sin_family = AF_INET; 144 dst_sin->sin_port = get_port(optarg); 145 dst_sin->sin_port = htons(dst_sin->sin_port); 146 n = inet_pton(AF_INET, optarg, &dst_sin->sin_addr); 147 if (n == 0) 148 errx(1, "-d: invalid inet address: %s", optarg); 149 else if (n < 0) 150 err(1, "-d: %s", optarg); 151 arg_mask |= INDST_MASK; 152 break; 153 154 case 's': 155 src_sin->sin_port = get_port(optarg); 156 src_sin->sin_port = htons(src_sin->sin_port); 157 n = inet_pton(AF_INET, optarg, &src_sin->sin_addr); 158 if (n == 0) 159 errx(1, "-s: invalid inet address: %s", optarg); 160 else if (n < 0) 161 err(1, "-s: %s", optarg); 162 arg_mask |= INSRC_MASK; 163 break; 164 165 case 'e': 166 strcpy(eaddr_str, "if0."); 167 strlcpy(&eaddr_str[strlen("if0.")], optarg, 168 sizeof(eaddr_str) - strlen("if0.")); 169 170 memset(&sdl, 0, sizeof(sdl)); 171 sdl.sdl_len = sizeof(sdl); 172 link_addr(eaddr_str, &sdl); 173 bcopy(LLADDR(&sdl), sa->sa_data, ETHER_ADDR_LEN); 174 arg_mask |= EADDR_MASK; 175 break; 176 177 case 'i': 178 strlcpy(conf.pc_ifname, optarg, sizeof(conf.pc_ifname)); 179 arg_mask |= IFACE_MASK; 180 break; 181 182 case 'm': 183 conf.pc_datalen = atoi(optarg); 184 break; 185 186 case 'l': 187 conf.pc_duration = atoi(optarg); 188 break; 189 190 case 'D': 191 dev = optarg; 192 break; 193 194 case 'q': 195 conf.pc_pktenq = atoi(optarg); 196 break; 197 198 case 'M': 199 start = PKTGENMQSTART; 200 break; 201 202 default: 203 usage(); 204 } 205 } 206 207 if ((arg_mask & MASK_NEEDED) != MASK_NEEDED) 208 usage(); 209 210 fd = open(dev, O_RDONLY); 211 if (fd < 0) 212 err(1, "open(%s)", dev); 213 214 if (ioctl(fd, PKTGENSCONF, &conf) < 0) 215 err(1, "ioctl(PKTGENSCONF)"); 216 217 if (ioctl(fd, start) < 0) { 218 err(1, "ioctl(%s)", 219 start == PKTGENSTART ? "PKTGENSTART" : "PKTGENMQSTART"); 220 } 221 222 close(fd); 223 exit(0); 224 } 225