VirtualBox

source: vbox/trunk/src/apps/adpctl/VBoxNetAdpCtl.cpp@ 25834

Last change on this file since 25834 was 25826, checked in by vboxsync, 15 years ago

VBoxNetAdpCtl, Main/NetIf: multiple vboxnet instance fixes for Solaris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: VBoxNetAdpCtl.cpp 25826 2010-01-14 10:59:36Z vboxsync $ */
2/** @file
3 * Apps - VBoxAdpCtl, Configuration tool for vboxnetX adapters.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <sys/wait.h>
32#include <sys/ioctl.h>
33#include <fcntl.h>
34#ifdef RT_OS_SOLARIS
35# include <sys/ioccom.h>
36#endif
37
38/** @todo Error codes must be moved to some header file */
39#define ADPCTLERR_BAD_NAME 2
40#define ADPCTLERR_NO_CTL_DEV 3
41#define ADPCTLERR_IOCTL_FAILED 4
42
43/** @todo These are duplicates from src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h */
44#define VBOXNETADP_CTL_DEV_NAME "/dev/vboxnetctl"
45#define VBOXNETADP_NAME "vboxnet"
46#define VBOXNETADP_MAX_NAME_LEN 32
47#define VBOXNETADP_CTL_ADD _IOR('v', 1, VBOXNETADPREQ)
48#define VBOXNETADP_CTL_REMOVE _IOW('v', 2, VBOXNETADPREQ)
49typedef struct VBoxNetAdpReq
50{
51 char szName[VBOXNETADP_MAX_NAME_LEN];
52} VBOXNETADPREQ;
53typedef VBOXNETADPREQ *PVBOXNETADPREQ;
54
55
56#define VBOXADPCTL_IFCONFIG_PATH "/sbin/ifconfig"
57
58#if defined(RT_OS_LINUX)
59# define VBOXADPCTL_DEL_CMD "del"
60# define VBOXADPCTL_ADD_CMD "add"
61#elif defined(RT_OS_SOLARIS)
62# define VBOXADPCTL_DEL_CMD "removeif"
63# define VBOXADPCTL_ADD_CMD "addif"
64#else
65# define VBOXADPCTL_DEL_CMD "delete"
66# define VBOXADPCTL_ADD_CMD "add"
67#endif
68
69static void showUsage(void)
70{
71 fprintf(stderr, "Usage: VBoxNetAdpCtl <adapter> <address> ([netmask <address>] | remove)\n");
72 fprintf(stderr, " | VBoxNetAdpCtl add\n");
73 fprintf(stderr, " | VBoxNetAdpCtl <adapter> remove\n");
74}
75
76static int executeIfconfig(const char *pcszAdapterName, const char *pcszArg1,
77 const char *pcszArg2 = NULL,
78 const char *pcszArg3 = NULL,
79 const char *pcszArg4 = NULL,
80 const char *pcszArg5 = NULL)
81{
82 const char * const argv[] =
83 {
84 VBOXADPCTL_IFCONFIG_PATH,
85 pcszAdapterName,
86 pcszArg1, /* [address family] */
87 pcszArg2, /* address */
88 pcszArg3, /* ['netmask'] */
89 pcszArg4, /* [network mask] */
90 pcszArg5, /* [network mask] */
91 NULL /* terminator */
92 };
93 char * const envp[] = { (char*)"LC_ALL=C", NULL };
94 int rc = EXIT_SUCCESS;
95 pid_t childPid = fork();
96 switch (childPid)
97 {
98 case -1: /* Something went wrong. */
99 perror("fork() failed");
100 rc = EXIT_FAILURE;
101 break;
102 case 0: /* Child process. */
103 if (execve(VBOXADPCTL_IFCONFIG_PATH, (char * const*)argv, envp) == -1)
104 rc = EXIT_FAILURE;
105 break;
106 default: /* Parent process. */
107 waitpid(childPid, &rc, 0);
108 break;
109 }
110
111 return rc;
112}
113
114#define MAX_ADDRESSES 128
115#define MAX_ADDRLEN 64
116
117static bool removeAddresses(char *pszAdapterName)
118{
119 char szBuf[1024];
120 char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN];
121 int rc;
122 int fds[2];
123 char * const argv[] = { (char*)VBOXADPCTL_IFCONFIG_PATH, pszAdapterName, NULL };
124 char * const envp[] = { (char*)"LC_ALL=C", NULL };
125
126 memset(aszAddresses, 0, sizeof(aszAddresses));
127
128 rc = pipe(fds);
129 if (rc < 0)
130 return false;
131
132 pid_t pid = fork();
133 if (pid < 0)
134 return false;
135
136 if (pid == 0)
137 {
138 /* child */
139 close(fds[0]);
140 close(STDOUT_FILENO);
141 rc = dup2(fds[1], STDOUT_FILENO);
142 if (rc >= 0)
143 execve(VBOXADPCTL_IFCONFIG_PATH, argv, envp);
144 return false;
145 }
146
147 /* parent */
148 close(fds[1]);
149 FILE *fp = fdopen(fds[0], "r");
150 if (!fp)
151 return false;
152
153 int cAddrs;
154 for (cAddrs = 0; cAddrs < MAX_ADDRESSES && fgets(szBuf, sizeof(szBuf), fp);)
155 {
156 int cbSkipWS = strspn(szBuf, " \t");
157 char *pszWord = strtok(szBuf + cbSkipWS, " ");
158 /* We are concerned with IPv6 address lines only. */
159 if (!pszWord || strcmp(pszWord, "inet6"))
160 continue;
161#ifdef RT_OS_LINUX
162 pszWord = strtok(NULL, " ");
163 /* Skip "addr:". */
164 if (!pszWord || strcmp(pszWord, "addr:"))
165 continue;
166#endif
167 pszWord = strtok(NULL, " ");
168 /* Skip link-local addresses. */
169 if (!pszWord || !strncmp(pszWord, "fe80", 4))
170 continue;
171 strncpy(aszAddresses[cAddrs++], pszWord, MAX_ADDRLEN-1);
172 }
173 fclose(fp);
174
175 for (int i = 0; i < cAddrs; i++)
176 {
177 if (executeIfconfig(pszAdapterName, "inet6",
178 VBOXADPCTL_DEL_CMD, aszAddresses[i]) != EXIT_SUCCESS)
179 return false;
180 }
181
182 return true;
183}
184
185int doIOCtl(unsigned long uCmd, void *pData)
186{
187 int fd = open(VBOXNETADP_CTL_DEV_NAME, O_RDWR);
188 if (fd == -1)
189 {
190 perror("VBoxNetAdpCtl: failed to open " VBOXNETADP_CTL_DEV_NAME);
191 return ADPCTLERR_NO_CTL_DEV;
192 }
193
194 int rc = ioctl(fd, uCmd, pData);
195 if (rc == -1)
196 {
197 perror("VBoxNetAdpCtl: ioctl failed for " VBOXNETADP_CTL_DEV_NAME);
198 rc = ADPCTLERR_IOCTL_FAILED;
199 }
200
201 close(fd);
202
203 return rc;
204}
205
206int checkAdapterName(const char *pcszNameIn, char *pszNameOut)
207{
208 int iAdapterIndex = -1;
209
210 if ( strlen(pcszNameIn) >= VBOXNETADP_MAX_NAME_LEN
211 || sscanf(pcszNameIn, "vboxnet%d", &iAdapterIndex) != 1
212 || iAdapterIndex < 0 || iAdapterIndex > 99 )
213 {
214 fprintf(stderr, "Setting configuration for %s is not supported.\n", pcszNameIn);
215 return ADPCTLERR_BAD_NAME;
216 }
217 sprintf(pszNameOut, "vboxnet%d", iAdapterIndex);
218 if (strcmp(pszNameOut, pcszNameIn))
219 {
220 fprintf(stderr, "Invalid adapter name %s.\n", pcszNameIn);
221 return ADPCTLERR_BAD_NAME;
222 }
223
224 return 0;
225}
226
227int main(int argc, char *argv[])
228
229{
230 char szAdapterName[VBOXNETADP_MAX_NAME_LEN];
231 char *pszAdapterName = NULL;
232 const char *pszAddress = NULL;
233 const char *pszNetworkMask = NULL;
234 const char *pszOption = NULL;
235 int rc = EXIT_SUCCESS;
236 bool fRemove = false;
237 VBOXNETADPREQ Req;
238
239 switch (argc)
240 {
241 case 5:
242 {
243 /* Add a netmask to existing interface */
244 if (strcmp("netmask", argv[3]))
245 {
246 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
247 showUsage();
248 return 1;
249 }
250 pszOption = "netmask";
251 pszNetworkMask = argv[4];
252 pszAdapterName = argv[1];
253 pszAddress = argv[2];
254 break;
255 }
256
257 case 4:
258 {
259 /* Remove a single address from existing interface */
260 if (strcmp("remove", argv[3]))
261 {
262 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
263 showUsage();
264 return 1;
265 }
266 fRemove = true;
267 pszAdapterName = argv[1];
268 pszAddress = argv[2];
269 break;
270 }
271
272 case 3:
273 {
274 /* Remove an existing interface */
275 pszAdapterName = argv[1];
276 pszAddress = argv[2];
277 if (strcmp("remove", pszAddress) == 0)
278 {
279 rc = checkAdapterName(pszAdapterName, szAdapterName);
280 if (rc)
281 return rc;
282#ifdef RT_OS_SOLARIS
283 return 1;
284#else
285 memset(&Req, '\0', sizeof(Req));
286 snprintf(Req.szName, sizeof(Req.szName), "%s", szAdapterName);
287 return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req);
288#endif
289 }
290 break;
291 }
292
293 case 2:
294 {
295 /* Create a new interface */
296 if (strcmp("add", argv[1]) == 0)
297 {
298#ifdef RT_OS_SOLARIS
299 return 1;
300#else
301 memset(&Req, '\0', sizeof(Req));
302 rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req);
303 if (rc == 0)
304 puts(Req.szName);
305#endif
306 return rc;
307 }
308 /* Fall through */
309 }
310
311 default:
312 fprintf(stderr, "Invalid number of arguments.\n\n");
313 /* Fall through */
314 case 1:
315 showUsage();
316 return 1;
317 }
318
319 rc = checkAdapterName(pszAdapterName, szAdapterName);
320 if (rc)
321 return rc;
322
323 pszAdapterName = szAdapterName;
324
325 if (fRemove)
326 {
327 if (strchr(pszAddress, ':'))
328 rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress);
329 else
330 {
331#if defined(RT_OS_LINUX)
332 rc = executeIfconfig(pszAdapterName, "0.0.0.0");
333#else
334 rc = executeIfconfig(pszAdapterName, VBOXADPCTL_DEL_CMD, pszAddress);
335#endif
336
337#ifdef RT_OS_SOLARIS
338 /* On Solaris we can unplumb the ipv4 interface */
339 executeIfconfig(pszAdapterName, "inet", "unplumb");
340#endif
341 }
342 }
343 else
344 {
345 /* We are setting/replacing address. */
346 if (strchr(pszAddress, ':'))
347 {
348#ifdef RT_OS_SOLARIS
349 /* On Solaris we need to plumb the interface first if it's not already plumbed. */
350 if (executeIfconfig(pszAdapterName, "inet6") != 0)
351 executeIfconfig(pszAdapterName, "inet6", "plumb", "up");
352#endif
353 /*
354 * Before we set IPv6 address we'd like to remove
355 * all previously assigned addresses except the
356 * self-assigned one.
357 */
358 if (!removeAddresses(pszAdapterName))
359 rc = EXIT_FAILURE;
360 else
361 rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_ADD_CMD, pszAddress, pszOption, pszNetworkMask);
362 }
363 else
364 {
365#ifdef RT_OS_SOLARIS
366 /* On Solaris we need to plumb the interface first if it's not already plumbed. */
367 if (executeIfconfig(pszAdapterName, "inet") != 0)
368 executeIfconfig(pszAdapterName, "plumb", "up");
369#endif
370 rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask);
371 }
372 }
373 return rc;
374}
375
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette