vbox的更動 67687 路徑 trunk/src/VBox/HostDrivers
- 時間撮記:
- 2017-6-29 上午10:18:32 (7 年 以前)
- 檔案:
-
- 修改 1 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/HostDrivers/adpctl/VBoxNetAdpCtl.cpp
r65649 r67687 21 21 * Header Files * 22 22 *********************************************************************************************************************************/ 23 #include <list> 24 #include <errno.h> 23 25 #include <stdio.h> 26 #include <stdarg.h> 24 27 #include <stdlib.h> 25 28 #include <string.h> … … 45 48 #endif 46 49 50 #define NOREF(x) (void)x 51 47 52 /** @todo Error codes must be moved to some header file */ 48 53 #define ADPCTLERR_BAD_NAME 2 … … 66 71 #define VBOXADPCTL_IFCONFIG_PATH1 "/sbin/ifconfig" 67 72 #define VBOXADPCTL_IFCONFIG_PATH2 "/bin/ifconfig" 68 static char *g_pszIfConfig; 69 70 #if defined(RT_OS_LINUX) 71 # define VBOXADPCTL_DEL_CMD "del" 72 # define VBOXADPCTL_ADD_CMD "add" 73 #elif defined(RT_OS_SOLARIS) 74 # define VBOXADPCTL_DEL_CMD "removeif" 75 # define VBOXADPCTL_ADD_CMD "addif" 76 #else 77 # define VBOXADPCTL_DEL_CMD "delete" 78 # define VBOXADPCTL_ADD_CMD "add" 79 #endif 73 80 74 81 75 static void showUsage(void) … … 86 80 } 87 81 88 static void setPathIfConfig(void) 89 { 90 struct stat s; 91 if ( !stat(VBOXADPCTL_IFCONFIG_PATH1, &s) 92 && S_ISREG(s.st_mode)) 93 g_pszIfConfig = (char*)VBOXADPCTL_IFCONFIG_PATH1; 94 else 95 g_pszIfConfig = (char*)VBOXADPCTL_IFCONFIG_PATH2; 96 } 97 98 static int executeIfconfig(const char *pcszAdapterName, const char *pcszArg1, 99 const char *pcszArg2 = NULL, 100 const char *pcszArg3 = NULL, 101 const char *pcszArg4 = NULL, 102 const char *pcszArg5 = NULL) 103 { 104 const char * const argv[] = 105 { 106 g_pszIfConfig, 107 pcszAdapterName, 108 pcszArg1, /* [address family] */ 109 pcszArg2, /* address */ 110 pcszArg3, /* ['netmask'] */ 111 pcszArg4, /* [network mask] */ 112 pcszArg5, /* [network mask] */ 113 NULL /* terminator */ 114 }; 115 char * const envp[] = { (char*)"LC_ALL=C", NULL }; 82 83 /* 84 * A wrapper on standard list that provides '<<' operator for adding several list members in a single 85 * line dynamically. For example: "CmdList(arg1) << arg2 << arg3" produces a list with three members. 86 */ 87 class CmdList 88 { 89 public: 90 /** Creates an empty list. */ 91 CmdList() {}; 92 /** Creates a list with a single member. */ 93 CmdList(const char *pcszCommand) { m_list.push_back(pcszCommand); }; 94 /** Provides access to the underlying standard list. */ 95 const std::list<const char *>& getList(void) const { return m_list; }; 96 /** Adds a member to the list. */ 97 CmdList& operator<<(const char *pcszArgument); 98 private: 99 std::list<const char *>m_list; 100 }; 101 102 CmdList& CmdList::operator<<(const char *pcszArgument) 103 { 104 m_list.push_back(pcszArgument); 105 return *this; 106 } 107 108 /** Simple helper to distinguish IPv4 and IPv6 addresses. */ 109 inline bool isAddrV6(const char *pcszAddress) 110 { 111 return !!(strchr(pcszAddress, ':')); 112 } 113 114 115 /********************************************************************************************************************************* 116 * Generic address commands. * 117 *********************************************************************************************************************************/ 118 119 /** 120 * The base class for all address manipulation commands. While being an abstract class, 121 * it provides a generic implementation of 'set' and 'remove' methods, which rely on 122 * pure virtual methods like 'addV4' and 'removeV4' to perform actual command execution. 123 */ 124 class AddressCommand 125 { 126 public: 127 AddressCommand() : m_pszPath(0) {}; 128 virtual ~AddressCommand() {}; 129 130 /** returns true if underlying command (executable) is present in the system. */ 131 bool isAvailable(void) 132 { struct stat s; return (!stat(m_pszPath, &s) && S_ISREG(s.st_mode)); }; 133 134 /* 135 * Someday we may want to support several IP addresses per adapter, but for now we 136 * have 'set' method only, which replaces all addresses with the one specifed. 137 * 138 * virtual int add(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0; 139 */ 140 /** replace existing address(es) */ 141 virtual int set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0); 142 /** remove address */ 143 virtual int remove(const char *pcszAdapter, const char *pcszAddress); 144 protected: 145 /** IPv4-specific handler used by generic implementation of 'set' method if 'setV4' is not supported. */ 146 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0; 147 /** IPv6-specific handler used by generic implementation of 'set' method. */ 148 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0; 149 /** IPv4-specific handler used by generic implementation of 'set' method. */ 150 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0; 151 /** IPv4-specific handler used by generic implementation of 'remove' method. */ 152 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) = 0; 153 /** IPv6-specific handler used by generic implementation of 'remove' method. */ 154 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress) = 0; 155 /** Composes the argument list of command that obtains all addresses assigned to the adapter. */ 156 virtual CmdList getShowCommand(const char *pcszAdapter) const = 0; 157 158 /** Prepares an array of C strings needed for 'exec' call. */ 159 char * const * allocArgv(const CmdList& commandList); 160 /** Hides process creation details. To be used in derived classes. */ 161 int execute(CmdList& commandList); 162 163 /** A path to executable command. */ 164 const char *m_pszPath; 165 private: 166 /** Removes all previously asssigned addresses of a particular protocol family. */ 167 int removeAddresses(const char *pcszAdapter, const char *pcszFamily); 168 }; 169 170 /* 171 * A generic implementation of 'ifconfig' command for all platforms. 172 */ 173 class CmdIfconfig : public AddressCommand 174 { 175 public: 176 CmdIfconfig() 177 { 178 struct stat s; 179 if ( !stat(VBOXADPCTL_IFCONFIG_PATH1, &s) 180 && S_ISREG(s.st_mode)) 181 m_pszPath = (char*)VBOXADPCTL_IFCONFIG_PATH1; 182 else 183 m_pszPath = (char*)VBOXADPCTL_IFCONFIG_PATH2; 184 }; 185 186 protected: 187 /** Returns platform-specific subcommand to add an address. */ 188 virtual const char *addCmdArg(void) const = 0; 189 /** Returns platform-specific subcommand to remove an address. */ 190 virtual const char *delCmdArg(void) const = 0; 191 virtual CmdList getShowCommand(const char *pcszAdapter) const 192 { return CmdList(pcszAdapter); }; 193 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 194 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); NOREF(pcszNetmask); }; 195 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 196 { 197 return execute(CmdList(pcszAdapter) << "inet6" << addCmdArg() << pcszAddress); 198 NOREF(pcszNetmask); 199 }; 200 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 201 { 202 if (!pcszNetmask) 203 return execute(CmdList(pcszAdapter) << pcszAddress); 204 return execute(CmdList(pcszAdapter) << pcszAddress << "netmask" << pcszNetmask); 205 }; 206 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) 207 { return execute(CmdList(pcszAdapter) << delCmdArg() << pcszAddress); }; 208 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress) 209 { return execute(CmdList(pcszAdapter) << "inet6" << delCmdArg() << pcszAddress); }; 210 }; 211 212 213 /********************************************************************************************************************************* 214 * Platform-specific commands * 215 *********************************************************************************************************************************/ 216 217 class CmdIfconfigLinux : public CmdIfconfig 218 { 219 protected: 220 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) 221 { return execute(CmdList(pcszAdapter) << "0.0.0.0"); NOREF(pcszAddress); }; 222 virtual const char *addCmdArg(void) const { return "add"; }; 223 virtual const char *delCmdArg(void) const { return "del"; }; 224 }; 225 226 class CmdIfconfigDarwin : public CmdIfconfig 227 { 228 protected: 229 virtual const char *addCmdArg(void) const { return "add"; }; 230 virtual const char *delCmdArg(void) const { return "delete"; }; 231 }; 232 233 class CmdIfconfigSolaris : public CmdIfconfig 234 { 235 public: 236 virtual int set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 237 { 238 const char *pcszFamily = isAddrV6(pcszAddress) ? "inet6" : "inet"; 239 if (execute(CmdList(pcszAdapter) << pcszFamily)) 240 execute(CmdList(pcszAdapter) << pcszFamily << "plumb" << "up"); 241 return CmdIfconfig::set(pcszAdapter, pcszAddress, pcszNetmask); 242 }; 243 protected: 244 /* We can umplumb IPv4 interfaces only! */ 245 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) 246 { 247 int rc = CmdIfconfig::removeV4(pcszAdapter, pcszAddress); 248 execute(CmdList(pcszAdapter) << "inet" << "unplumb"); 249 return rc; 250 }; 251 virtual const char *addCmdArg(void) const { return "addif"; }; 252 virtual const char *delCmdArg(void) const { return "removeif"; }; 253 }; 254 255 256 /* 257 * Linux-specific implementation of 'ip' command, as other platforms do not support it. 258 */ 259 class CmdIpLinux : public AddressCommand 260 { 261 public: 262 CmdIpLinux() { pszBuffer = 0; m_pszPath = "/sbin/ip"; }; 263 virtual ~CmdIpLinux() { delete pszBuffer; }; 264 /** 265 * IPv4 and IPv6 syntax is the same, so we override `remove` instead of implementing 266 * family-specific commands. It would be easier to use the same body in both 267 * 'removeV4' and 'removeV6', so we override 'remove' to illustrate how to do common 268 * implementation. 269 */ 270 virtual int remove(const char *pcszAdapter, const char *pcszAddress) 271 { return execute(CmdList("addr") << "del" << pcszAddress << "dev" << pcszAdapter); }; 272 protected: 273 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 274 { 275 return execute(CmdList("addr") << "add" << combine(pcszAddress, pcszNetmask) << 276 "dev" << pcszAdapter); 277 }; 278 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 279 { 280 return execute(CmdList("addr") << "add" << pcszAddress << "dev" << pcszAdapter); 281 NOREF(pcszNetmask); 282 }; 283 /** 284 * Our command does not support 'replacing' addresses. Reporting this fact to generic implementation 285 * of 'set' causes it to remove all assigned addresses, then 'add' the new one. 286 */ 287 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) 288 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); NOREF(pcszNetmask); }; 289 /** We use family-agnostic command syntax. See 'remove' above. */ 290 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) 291 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); }; 292 /** We use family-agnostic command syntax. See 'remove' above. */ 293 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress) 294 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); }; 295 virtual CmdList getShowCommand(const char *pcszAdapter) const 296 { return CmdList("addr") << "show" << "dev" << pcszAdapter; }; 297 private: 298 /** Converts address and network mask into a single string in CIDR notation (like 192.168.1.1/24) */ 299 const char *combine(const char *pcszAddress, const char *pcszNetmask); 300 301 char *pszBuffer; 302 }; 303 304 const char * CmdIpLinux::combine(const char *pcszAddress, const char *pcszNetmask) 305 { 306 delete pszBuffer; 307 if (pcszNetmask) 308 { 309 unsigned cBits = 0; 310 unsigned m[4]; 311 if (sscanf(pcszNetmask, "%u.%u.%u.%u", &m[0], &m[1], &m[2], &m[3]) == 4) 312 { 313 for (int i = 0; i < 4 && m[i]; ++i) 314 { 315 int mask = m[i]; 316 while (mask & 0x80) 317 { 318 cBits++; 319 mask <<= 1; 320 } 321 } 322 pszBuffer = new char[strlen(pcszAddress) + 4]; // '/xx\0' 323 sprintf(pszBuffer, "%s/%u", pcszAddress, cBits); 324 return pszBuffer; 325 } 326 } 327 return pcszAddress; 328 } 329 330 331 332 /********************************************************************************************************************************* 333 * Generic address command implementations * 334 *********************************************************************************************************************************/ 335 336 int AddressCommand::set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask) 337 { 338 if (isAddrV6(pcszAddress)) 339 { 340 removeAddresses(pcszAdapter, "inet6"); 341 return addV6(pcszAdapter, pcszAddress, pcszNetmask); 342 } 343 int rc = setV4(pcszAdapter, pcszAddress, pcszNetmask); 344 if (rc == ENOTSUP) 345 { 346 removeAddresses(pcszAdapter, "inet"); 347 rc = addV4(pcszAdapter, pcszAddress, pcszNetmask); 348 } 349 return rc; 350 } 351 352 int AddressCommand::remove(const char *pcszAdapter, const char *pcszAddress) 353 { 354 if (isAddrV6(pcszAddress)) 355 return removeV6(pcszAdapter, pcszAddress); 356 return removeV4(pcszAdapter, pcszAddress); 357 } 358 359 /* 360 * Allocate an array of exec arguments. In addition to arguments provided 361 * we need to include the full path to the executable as well as "terminating" 362 * null pointer marking the end of the array. 363 */ 364 char * const * AddressCommand::allocArgv(const CmdList& list) 365 { 366 int i = 0; 367 std::list<const char *>::const_iterator it; 368 const char **argv = (const char **)calloc(list.getList().size() + 2, sizeof(const char *)); 369 if (argv) 370 { 371 argv[i++] = m_pszPath; 372 for (it = list.getList().begin(); it != list.getList().end(); ++it) 373 argv[i++] = *it; 374 argv[i++] = NULL; 375 } 376 return (char * const*)argv; 377 } 378 379 int AddressCommand::execute(CmdList& list) 380 { 381 char * const pEnv[] = { (char*)"LC_ALL=C", NULL }; 382 char * const* argv = allocArgv(list); 383 if (argv == NULL) 384 return EXIT_FAILURE; 385 116 386 int rc = EXIT_SUCCESS; 117 387 pid_t childPid = fork(); … … 123 393 break; 124 394 case 0: /* Child process. */ 125 if (execve(argv[0], (char * const*)argv, envp) == -1)395 if (execve(argv[0], argv, pEnv) == -1) 126 396 rc = EXIT_FAILURE; 127 397 break; … … 131 401 } 132 402 403 free((void*)argv); 133 404 return rc; 134 405 } … … 137 408 #define MAX_ADDRLEN 64 138 409 139 static bool removeAddresses(char *pszAdapterName)410 int AddressCommand::removeAddresses(const char *pcszAdapter, const char *pcszFamily) 140 411 { 141 412 char szBuf[1024]; 142 413 char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN]; 143 int rc ;414 int rc = EXIT_SUCCESS; 144 415 int fds[2]; 145 char * const argv[] = { g_pszIfConfig, pszAdapterName, NULL };416 char * const * argv = allocArgv(getShowCommand(pcszAdapter)); 146 417 char * const envp[] = { (char*)"LC_ALL=C", NULL }; 147 418 … … 150 421 rc = pipe(fds); 151 422 if (rc < 0) 152 return false;423 return errno; 153 424 154 425 pid_t pid = fork(); 155 426 if (pid < 0) 156 return false;427 return errno; 157 428 158 429 if (pid == 0) … … 163 434 rc = dup2(fds[1], STDOUT_FILENO); 164 435 if (rc >= 0) 165 execve(argv[0], argv, envp); 166 return false; 436 if (execve(argv[0], argv, envp) == -1) 437 return errno; 438 return rc; 167 439 } 168 440 … … 178 450 int cbSkipWS = strspn(szBuf, " \t"); 179 451 char *pszWord = strtok(szBuf + cbSkipWS, " "); 180 /* We are concerned with IPv6address lines only. */181 if (!pszWord || strcmp(pszWord, "inet6"))452 /* We are concerned with particular family address lines only. */ 453 if (!pszWord || strcmp(pszWord, pcszFamily)) 182 454 continue; 183 #ifdef RT_OS_LINUX 455 184 456 pszWord = strtok(NULL, " "); 185 /* Skip "addr:". */ 186 if (!pszWord || strcmp(pszWord, "addr:"))187 continue;188 #endif 189 pszWord = strtok(NULL, " "); 190 /* Skip link-local address es. */457 458 /* Skip "addr:" word if present. */ 459 if (pszWord && !strcmp(pszWord, "addr:")) 460 pszWord = strtok(NULL, " "); 461 462 /* Skip link-local address lines. */ 191 463 if (!pszWord || !strncmp(pszWord, "fe80", 4)) 192 464 continue; … … 195 467 fclose(fp); 196 468 197 for (int i = 0; i < cAddrs; i++) 198 { 199 if (executeIfconfig(pszAdapterName, "inet6", 200 VBOXADPCTL_DEL_CMD, aszAddresses[i]) != EXIT_SUCCESS) 201 return false; 202 } 203 204 return true; 205 } 206 207 208 #ifndef RT_OS_SOLARIS 209 static int doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq) 469 for (int i = 0; i < cAddrs && rc == EXIT_SUCCESS; i++) 470 rc = remove(pcszAdapter, aszAddresses[i]); 471 472 return rc; 473 } 474 475 476 /********************************************************************************************************************************* 477 * Adapter creation/removal implementations * 478 *********************************************************************************************************************************/ 479 480 /* 481 * A generic implementation of adapter creation/removal ioctl calls. 482 */ 483 class Adapter 484 { 485 public: 486 int add(char *pszNameInOut); 487 int remove(const char *pcszName); 488 int checkName(const char *pcszNameIn, char *pszNameOut); 489 protected: 490 virtual int doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq); 491 }; 492 493 /* 494 * Solaris does not support dynamic creation/removal of adapters. 495 */ 496 class AdapterSolaris : public Adapter 497 { 498 protected: 499 virtual int doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq) 500 { return 1 /*ENOTSUP*/; NOREF(iCmd); NOREF(pReq); }; 501 }; 502 503 #if defined(RT_OS_LINUX) 504 /* 505 * Linux implementation provides a 'workaround' to obtain adapter speed. 506 */ 507 class AdapterLinux : public Adapter 508 { 509 public: 510 int getSpeed(const char *pszName, unsigned *puSpeed); 511 }; 512 513 int AdapterLinux::getSpeed(const char *pszName, unsigned *puSpeed) 514 { 515 struct ifreq IfReq; 516 struct ethtool_value EthToolVal; 517 struct ethtool_cmd EthToolReq; 518 int fd = socket(AF_INET, SOCK_DGRAM, 0); 519 if (fd < 0) 520 { 521 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 522 "speed for %s: ", pszName); 523 perror("VBoxNetAdpCtl: failed to open control socket"); 524 return ADPCTLERR_SOCKET_FAILED; 525 } 526 /* Get link status first. */ 527 memset(&EthToolVal, 0, sizeof(EthToolVal)); 528 memset(&IfReq, 0, sizeof(IfReq)); 529 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszName); 530 531 EthToolVal.cmd = ETHTOOL_GLINK; 532 IfReq.ifr_data = (caddr_t)&EthToolVal; 533 int rc = ioctl(fd, SIOCETHTOOL, &IfReq); 534 if (rc == 0) 535 { 536 if (EthToolVal.data) 537 { 538 memset(&IfReq, 0, sizeof(IfReq)); 539 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszName); 540 EthToolReq.cmd = ETHTOOL_GSET; 541 IfReq.ifr_data = (caddr_t)&EthToolReq; 542 rc = ioctl(fd, SIOCETHTOOL, &IfReq); 543 if (rc == 0) 544 { 545 *puSpeed = EthToolReq.speed; 546 } 547 else 548 { 549 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 550 "speed for %s: ", pszName); 551 perror("VBoxNetAdpCtl: ioctl failed"); 552 rc = ADPCTLERR_IOCTL_FAILED; 553 } 554 } 555 else 556 *puSpeed = 0; 557 } 558 else 559 { 560 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 561 "status for %s: ", pszName); 562 perror("VBoxNetAdpCtl: ioctl failed"); 563 rc = ADPCTLERR_IOCTL_FAILED; 564 } 565 566 close(fd); 567 return rc; 568 } 569 #endif /* defined(RT_OS_LINUX) */ 570 571 int Adapter::add(char *pszName /* in/out */) 572 { 573 VBOXNETADPREQ Req; 574 memset(&Req, '\0', sizeof(Req)); 575 snprintf(Req.szName, sizeof(Req.szName), "%s", pszName); 576 int rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); 577 if (rc == 0) 578 strncpy(pszName, Req.szName, VBOXNETADP_MAX_NAME_LEN); 579 return rc; 580 } 581 582 int Adapter::remove(const char *pcszName) 583 { 584 VBOXNETADPREQ Req; 585 memset(&Req, '\0', sizeof(Req)); 586 snprintf(Req.szName, sizeof(Req.szName), "%s", pcszName); 587 return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req); 588 } 589 590 int Adapter::checkName(const char *pcszNameIn, char *pszNameOut) 591 { 592 int iAdapterIndex = -1; 593 594 if ( strlen(pcszNameIn) >= VBOXNETADP_MAX_NAME_LEN 595 || sscanf(pcszNameIn, "vboxnet%d", &iAdapterIndex) != 1 596 || iAdapterIndex < 0 || iAdapterIndex >= VBOXNETADP_MAX_INSTANCES ) 597 { 598 fprintf(stderr, "VBoxNetAdpCtl: Setting configuration for '%s' is not supported.\n", pcszNameIn); 599 return ADPCTLERR_BAD_NAME; 600 } 601 sprintf(pszNameOut, "vboxnet%d", iAdapterIndex); 602 if (strcmp(pszNameOut, pcszNameIn)) 603 { 604 fprintf(stderr, "VBoxNetAdpCtl: Invalid adapter name '%s'.\n", pcszNameIn); 605 return ADPCTLERR_BAD_NAME; 606 } 607 608 return 0; 609 } 610 611 int Adapter::doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq) 210 612 { 211 613 int fd = open(VBOXNETADP_CTL_DEV_NAME, O_RDWR); … … 233 635 return rc; 234 636 } 235 #endif /* !RT_OS_SOLARIS */ 236 237 238 static int checkAdapterName(const char *pcszNameIn, char *pszNameOut) 239 { 240 int iAdapterIndex = -1; 241 242 if ( strlen(pcszNameIn) >= VBOXNETADP_MAX_NAME_LEN 243 || sscanf(pcszNameIn, "vboxnet%d", &iAdapterIndex) != 1 244 || iAdapterIndex < 0 || iAdapterIndex >= VBOXNETADP_MAX_INSTANCES ) 245 { 246 fprintf(stderr, "VBoxNetAdpCtl: Setting configuration for '%s' is not supported.\n", pcszNameIn); 247 return ADPCTLERR_BAD_NAME; 248 } 249 sprintf(pszNameOut, "vboxnet%d", iAdapterIndex); 250 if (strcmp(pszNameOut, pcszNameIn)) 251 { 252 fprintf(stderr, "VBoxNetAdpCtl: Invalid adapter name '%s'.\n", pcszNameIn); 253 return ADPCTLERR_BAD_NAME; 254 } 255 256 return 0; 637 638 /********************************************************************************************************************************* 639 * Main logic, argument parsing, etc. * 640 *********************************************************************************************************************************/ 641 642 #if defined(RT_OS_LINUX) 643 static CmdIfconfigLinux g_ifconfig; 644 static AdapterLinux g_adapter; 645 #elif defined(RT_OS_SOLARIS) 646 static CmdIfconfigSolaris g_ifconfig; 647 static AdapterSolaris g_adapter; 648 #else 649 static CmdIfconfigDarwin g_ifconfig; 650 static Adapter g_adapter; 651 #endif 652 653 static AddressCommand& chooseAddressCommand() 654 { 655 #if defined(RT_OS_LINUX) 656 static CmdIpLinux g_ip; 657 if (g_ip.isAvailable()) 658 return g_ip; 659 #endif 660 return g_ifconfig; 257 661 } 258 662 … … 260 664 { 261 665 char szAdapterName[VBOXNETADP_MAX_NAME_LEN]; 262 char *pszAdapterName = NULL;263 const char *pszAddress = NULL;264 const char *pszNetworkMask = NULL;265 const char *pszOption = NULL;266 666 int rc = EXIT_SUCCESS; 267 bool fRemove = false; 268 VBOXNETADPREQ Req; 269 270 setPathIfConfig(); 667 668 AddressCommand& cmd = chooseAddressCommand(); 669 670 if (argc < 2) 671 { 672 fprintf(stderr, "Insufficient number of arguments\n\n"); 673 showUsage(); 674 return 1; 675 } 676 else if (argc == 2 && !strcmp("add", argv[1])) 677 { 678 /* Create a new interface */ 679 *szAdapterName = '\0'; 680 rc = g_adapter.add(szAdapterName); 681 if (rc == 0) 682 puts(szAdapterName); 683 return rc; 684 } 685 #ifdef RT_OS_LINUX 686 else if (argc == 3 && !strcmp("speed", argv[2])) 687 { 688 /* 689 * This ugly hack is needed for retrieving the link speed on 690 * pre-2.6.33 kernels (see @bugref{6345}). 691 */ 692 if (strlen(argv[1]) >= IFNAMSIZ) 693 { 694 showUsage(); 695 return -1; 696 } 697 unsigned uSpeed = 0; 698 rc = g_adapter.getSpeed(argv[1], &uSpeed); 699 if (!rc) 700 printf("%u", uSpeed); 701 return rc; 702 } 703 #endif 704 705 rc = g_adapter.checkName(argv[1], szAdapterName); 706 if (rc) 707 return rc; 271 708 272 709 switch (argc) … … 281 718 return 1; 282 719 } 283 pszOption = "netmask"; 284 pszNetworkMask = argv[4]; 285 pszAdapterName = argv[1]; 286 pszAddress = argv[2]; 720 rc = cmd.set(argv[1], argv[2], argv[4]); 287 721 break; 288 722 } … … 297 731 return 1; 298 732 } 299 fRemove = true; 300 pszAdapterName = argv[1]; 301 pszAddress = argv[2]; 733 rc = cmd.remove(argv[1], argv[2]); 302 734 break; 303 735 } … … 305 737 case 3: 306 738 { 307 pszAdapterName = argv[1]; 308 memset(&Req, '\0', sizeof(Req)); 309 #ifdef RT_OS_LINUX 310 if (strcmp("speed", argv[2]) == 0) 311 { 312 /* 313 * This ugly hack is needed for retrieving the link speed on 314 * pre-2.6.33 kernels (see @bugref{6345}). 315 */ 316 if (strlen(pszAdapterName) >= IFNAMSIZ) 317 { 318 showUsage(); 319 return -1; 320 } 321 struct ifreq IfReq; 322 struct ethtool_value EthToolVal; 323 struct ethtool_cmd EthToolReq; 324 int fd = socket(AF_INET, SOCK_DGRAM, 0); 325 if (fd < 0) 326 { 327 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 328 "speed for %s: ", pszAdapterName); 329 perror("VBoxNetAdpCtl: failed to open control socket"); 330 return ADPCTLERR_SOCKET_FAILED; 331 } 332 /* Get link status first. */ 333 memset(&EthToolVal, 0, sizeof(EthToolVal)); 334 memset(&IfReq, 0, sizeof(IfReq)); 335 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszAdapterName); 336 337 EthToolVal.cmd = ETHTOOL_GLINK; 338 IfReq.ifr_data = (caddr_t)&EthToolVal; 339 rc = ioctl(fd, SIOCETHTOOL, &IfReq); 340 if (rc == 0) 341 { 342 if (EthToolVal.data) 343 { 344 memset(&IfReq, 0, sizeof(IfReq)); 345 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszAdapterName); 346 EthToolReq.cmd = ETHTOOL_GSET; 347 IfReq.ifr_data = (caddr_t)&EthToolReq; 348 rc = ioctl(fd, SIOCETHTOOL, &IfReq); 349 if (rc == 0) 350 { 351 printf("%u", EthToolReq.speed); 352 } 353 else 354 { 355 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 356 "speed for %s: ", pszAdapterName); 357 perror("VBoxNetAdpCtl: ioctl failed"); 358 rc = ADPCTLERR_IOCTL_FAILED; 359 } 360 } 361 else 362 printf("0"); 363 } 364 else 365 { 366 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " 367 "status for %s: ", pszAdapterName); 368 perror("VBoxNetAdpCtl: ioctl failed"); 369 rc = ADPCTLERR_IOCTL_FAILED; 370 } 371 372 close(fd); 373 return rc; 374 } 375 #endif 376 rc = checkAdapterName(pszAdapterName, szAdapterName); 377 if (rc) 378 return rc; 379 snprintf(Req.szName, sizeof(Req.szName), "%s", szAdapterName); 380 pszAddress = argv[2]; 381 if (strcmp("remove", pszAddress) == 0) 739 if (strcmp("remove", argv[2]) == 0) 382 740 { 383 741 /* Remove an existing interface */ 384 #ifdef RT_OS_SOLARIS 385 return 1; 386 #else 387 return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req); 388 #endif 742 rc = g_adapter.remove(argv[1]); 389 743 } 390 else if (strcmp("add", pszAddress) == 0)744 else if (strcmp("add", argv[2]) == 0) 391 745 { 392 746 /* Create an interface with given name */ 393 #ifdef RT_OS_SOLARIS 394 return 1; 395 #else 396 rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); 747 rc = g_adapter.add(szAdapterName); 397 748 if (rc == 0) 398 puts(Req.szName); 399 #endif 400 return rc; 749 puts(szAdapterName); 401 750 } 751 else 752 rc = cmd.set(argv[1], argv[2]); 402 753 break; 403 754 } 404 755 405 case 2:406 {407 /* Create a new interface */408 if (strcmp("add", argv[1]) == 0)409 {410 #ifdef RT_OS_SOLARIS411 return 1;412 #else413 memset(&Req, '\0', sizeof(Req));414 rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req);415 if (rc == 0)416 puts(Req.szName);417 #endif418 return rc;419 }420 }421 /* fall thru */422 423 756 default: 424 757 fprintf(stderr, "Invalid number of arguments.\n\n"); 425 /* fall thru */426 case 1:427 758 showUsage(); 428 759 return 1; 429 760 } 430 761 431 rc = checkAdapterName(pszAdapterName, szAdapterName);432 if (rc)433 return rc;434 435 pszAdapterName = szAdapterName;436 437 if (fRemove)438 {439 if (strchr(pszAddress, ':'))440 rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress);441 else442 {443 #if defined(RT_OS_LINUX)444 rc = executeIfconfig(pszAdapterName, "0.0.0.0");445 #else446 rc = executeIfconfig(pszAdapterName, VBOXADPCTL_DEL_CMD, pszAddress);447 #endif448 449 #ifdef RT_OS_SOLARIS450 /* On Solaris we can unplumb the ipv4 interface */451 executeIfconfig(pszAdapterName, "inet", "unplumb");452 #endif453 }454 }455 else456 {457 /* We are setting/replacing address. */458 if (strchr(pszAddress, ':'))459 {460 #ifdef RT_OS_SOLARIS461 /* On Solaris we need to plumb the interface first if it's not already plumbed. */462 if (executeIfconfig(pszAdapterName, "inet6") != 0)463 executeIfconfig(pszAdapterName, "inet6", "plumb", "up");464 #endif465 /*466 * Before we set IPv6 address we'd like to remove467 * all previously assigned addresses except the468 * self-assigned one.469 */470 if (!removeAddresses(pszAdapterName))471 rc = EXIT_FAILURE;472 else473 rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_ADD_CMD, pszAddress, pszOption, pszNetworkMask);474 }475 else476 {477 #ifdef RT_OS_SOLARIS478 /* On Solaris we need to plumb the interface first if it's not already plumbed. */479 if (executeIfconfig(pszAdapterName, "inet") != 0)480 executeIfconfig(pszAdapterName, "plumb", "up");481 #endif482 rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask);483 }484 }485 762 return rc; 486 763 }
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器