Print this page
    
NEX-9538 dladm_str2bw() does not reset errno which is checked after string conversion
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-9184 libdladm/dlmgmtd should do a better link name validation
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libdladm/common/libdladm.c
          +++ new/usr/src/lib/libdladm/common/libdladm.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   */
  24   24  
  25   25  #include <unistd.h>
  26   26  #include <errno.h>
  27   27  #include <ctype.h>
  28   28  #include <fcntl.h>
  29   29  #include <strings.h>
  30   30  #include <dirent.h>
  31   31  #include <stdlib.h>
  32   32  #include <netinet/in.h>
  33   33  #include <arpa/inet.h>
  34   34  #include <sys/param.h>
  35   35  #include <sys/stat.h>
  36   36  #include <sys/dld.h>
  37   37  #include <sys/dld_ioc.h>
  38   38  #include <libdladm_impl.h>
  39   39  #include <libintl.h>
  40   40  #include <libdlpi.h>
  41   41  #include <libdllink.h>
  42   42  
  43   43  static char     dladm_rootdir[MAXPATHLEN] = "/";
  44   44  
  45   45  typedef struct media_type_desc {
  46   46          uint32_t        media_type;
  47   47  #define MAX_MEDIA_TYPE_STRING   32
  48   48          const char      media_type_str[MAX_MEDIA_TYPE_STRING];
  49   49  } media_type_t;
  50   50  
  51   51  static media_type_t media_type_table[] =  {
  52   52          { DL_ETHER,     "Ethernet" },
  53   53          { DL_WIFI,      "WiFi" },
  54   54          { DL_IB,        "Infiniband" },
  55   55          { DL_IPV4,      "IPv4Tunnel" },
  56   56          { DL_IPV6,      "IPv6Tunnel" },
  57   57          { DL_6TO4,      "6to4Tunnel" },
  58   58          { DL_CSMACD,    "CSMA/CD" },
  59   59          { DL_TPB,       "TokenBus" },
  60   60          { DL_TPR,       "TokenRing" },
  61   61          { DL_METRO,     "MetroNet" },
  62   62          { DL_HDLC,      "HDLC" },
  63   63          { DL_CHAR,      "SyncCharacter" },
  64   64          { DL_CTCA,      "CTCA" },
  65   65          { DL_FDDI,      "FDDI" },
  66   66          { DL_FC,        "FiberChannel" },
  67   67          { DL_ATM,       "ATM" },
  68   68          { DL_IPATM,     "ATM(ClassicIP)" },
  69   69          { DL_X25,       "X.25" },
  70   70          { DL_IPX25,     "X.25(ClassicIP)" },
  71   71          { DL_ISDN,      "ISDN" },
  72   72          { DL_HIPPI,     "HIPPI" },
  73   73          { DL_100VG,     "100BaseVGEthernet" },
  74   74          { DL_100VGTPR,  "100BaseVGTokenRing" },
  75   75          { DL_ETH_CSMA,  "IEEE802.3" },
  76   76          { DL_100BT,     "100BaseT" },
  77   77          { DL_FRAME,     "FrameRelay" },
  78   78          { DL_MPFRAME,   "MPFrameRelay" },
  79   79          { DL_ASYNC,     "AsyncCharacter" },
  80   80          { DL_IPNET,     "IPNET" },
  81   81          { DL_OTHER,     "Other" }
  82   82  };
  83   83  #define MEDIATYPECOUNT  (sizeof (media_type_table) / sizeof (media_type_t))
  84   84  
  85   85  typedef struct {
  86   86          uint32_t        lp_type;
  87   87          char            *lp_name;
  88   88  } link_protect_t;
  89   89  
  90   90  static link_protect_t link_protect_types[] = {
  91   91          { MPT_MACNOSPOOF, "mac-nospoof" },
  92   92          { MPT_RESTRICTED, "restricted" },
  93   93          { MPT_IPNOSPOOF, "ip-nospoof" },
  94   94          { MPT_DHCPNOSPOOF, "dhcp-nospoof" }
  95   95  };
  96   96  #define LPTYPES (sizeof (link_protect_types) / sizeof (link_protect_t))
  97   97  
  98   98  dladm_status_t
  99   99  dladm_open(dladm_handle_t *handle)
 100  100  {
 101  101          int dld_fd;
 102  102  
 103  103          if (handle == NULL)
 104  104                  return (DLADM_STATUS_BADARG);
 105  105  
 106  106          if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
 107  107                  return (dladm_errno2status(errno));
 108  108  
 109  109          /*
 110  110           * Don't open DLMGMT_DOOR now.  dlmgmtd(1M) is not able to
 111  111           * open the door when the dladm handle is opened because the
 112  112           * door hasn't been created yet at that time.  Thus, we must
 113  113           * open it on-demand in dladm_door_fd().  Move the open()
 114  114           * to dladm_door_fd() for all cases.
 115  115           */
 116  116  
 117  117          if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) {
 118  118                  (void) close(dld_fd);
 119  119                  return (DLADM_STATUS_NOMEM);
 120  120          }
 121  121  
 122  122          (*handle)->dld_fd = dld_fd;
 123  123          (*handle)->door_fd = -1;
 124  124  
 125  125          return (DLADM_STATUS_OK);
 126  126  }
 127  127  
 128  128  void
 129  129  dladm_close(dladm_handle_t handle)
 130  130  {
 131  131          if (handle != NULL) {
 132  132                  (void) close(handle->dld_fd);
 133  133                  if (handle->door_fd != -1)
 134  134                          (void) close(handle->door_fd);
 135  135                  free(handle);
 136  136          }
 137  137  }
 138  138  
 139  139  int
 140  140  dladm_dld_fd(dladm_handle_t handle)
 141  141  {
 142  142          return (handle->dld_fd);
 143  143  }
 144  144  
 145  145  /*
 146  146   * If DLMGMT_DOOR hasn't been opened in the handle yet, open it.
 147  147   */
 148  148  dladm_status_t
 149  149  dladm_door_fd(dladm_handle_t handle, int *door_fd)
 150  150  {
 151  151          int fd;
 152  152  
 153  153          if (handle->door_fd == -1) {
 154  154                  if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0)
 155  155                          return (dladm_errno2status(errno));
 156  156                  handle->door_fd = fd;
 157  157          }
 158  158          *door_fd = handle->door_fd;
 159  159  
 160  160          return (DLADM_STATUS_OK);
 161  161  }
 162  162  
 163  163  const char *
 164  164  dladm_status2str(dladm_status_t status, char *buf)
 165  165  {
 166  166          const char      *s;
 167  167  
 168  168          switch (status) {
 169  169          case DLADM_STATUS_OK:
 170  170                  s = "ok";
 171  171                  break;
 172  172          case DLADM_STATUS_BADARG:
 173  173                  s = "invalid argument";
 174  174                  break;
 175  175          case DLADM_STATUS_FAILED:
 176  176                  s = "operation failed";
 177  177                  break;
 178  178          case DLADM_STATUS_TOOSMALL:
 179  179                  s = "buffer size too small";
 180  180                  break;
 181  181          case DLADM_STATUS_NOTSUP:
 182  182                  s = "operation not supported";
 183  183                  break;
 184  184          case DLADM_STATUS_NOTFOUND:
 185  185                  s = "object not found";
 186  186                  break;
 187  187          case DLADM_STATUS_BADVAL:
 188  188                  s = "invalid value";
 189  189                  break;
 190  190          case DLADM_STATUS_NOMEM:
 191  191                  s = "insufficient memory";
 192  192                  break;
 193  193          case DLADM_STATUS_EXIST:
 194  194                  s = "object already exists";
 195  195                  break;
 196  196          case DLADM_STATUS_LINKINVAL:
 197  197                  s = "invalid link";
 198  198                  break;
 199  199          case DLADM_STATUS_PROPRDONLY:
 200  200                  s = "read-only property";
 201  201                  break;
 202  202          case DLADM_STATUS_BADVALCNT:
 203  203                  s = "invalid number of values";
 204  204                  break;
 205  205          case DLADM_STATUS_DBNOTFOUND:
 206  206                  s = "database not found";
 207  207                  break;
 208  208          case DLADM_STATUS_DENIED:
 209  209                  s = "permission denied";
 210  210                  break;
 211  211          case DLADM_STATUS_IOERR:
 212  212                  s = "I/O error";
 213  213                  break;
 214  214          case DLADM_STATUS_TEMPONLY:
 215  215                  s = "change cannot be persistent";
 216  216                  break;
 217  217          case DLADM_STATUS_TIMEDOUT:
 218  218                  s = "operation timed out";
 219  219                  break;
 220  220          case DLADM_STATUS_ISCONN:
 221  221                  s = "already connected";
 222  222                  break;
 223  223          case DLADM_STATUS_NOTCONN:
 224  224                  s = "not connected";
 225  225                  break;
 226  226          case DLADM_STATUS_REPOSITORYINVAL:
 227  227                  s = "invalid configuration repository";
 228  228                  break;
 229  229          case DLADM_STATUS_MACADDRINVAL:
 230  230                  s = "invalid MAC address";
 231  231                  break;
 232  232          case DLADM_STATUS_KEYINVAL:
 233  233                  s = "invalid key";
 234  234                  break;
 235  235          case DLADM_STATUS_INVALIDMACADDRLEN:
 236  236                  s = "invalid MAC address length";
 237  237                  break;
 238  238          case DLADM_STATUS_INVALIDMACADDRTYPE:
 239  239                  s = "invalid MAC address type";
 240  240                  break;
 241  241          case DLADM_STATUS_LINKBUSY:
 242  242                  s = "link busy";
 243  243                  break;
 244  244          case DLADM_STATUS_VIDINVAL:
 245  245                  s = "invalid VLAN identifier";
 246  246                  break;
 247  247          case DLADM_STATUS_TRYAGAIN:
 248  248                  s = "try again later";
 249  249                  break;
 250  250          case DLADM_STATUS_NONOTIF:
 251  251                  s = "link notification is not supported";
 252  252                  break;
 253  253          case DLADM_STATUS_BADTIMEVAL:
 254  254                  s = "invalid time range";
 255  255                  break;
 256  256          case DLADM_STATUS_INVALIDMACADDR:
 257  257                  s = "invalid MAC address value";
 258  258                  break;
 259  259          case DLADM_STATUS_INVALIDMACADDRNIC:
 260  260                  s = "MAC address reserved for use by underlying data-link";
 261  261                  break;
 262  262          case DLADM_STATUS_INVALIDMACADDRINUSE:
 263  263                  s = "MAC address is already in use";
 264  264                  break;
 265  265          case DLADM_STATUS_MACFACTORYSLOTINVALID:
 266  266                  s = "invalid factory MAC address slot";
 267  267                  break;
 268  268          case DLADM_STATUS_MACFACTORYSLOTUSED:
 269  269                  s = "factory MAC address slot already used";
 270  270                  break;
 271  271          case DLADM_STATUS_MACFACTORYSLOTALLUSED:
 272  272                  s = "all factory MAC address slots are in use";
 273  273                  break;
 274  274          case DLADM_STATUS_MACFACTORYNOTSUP:
 275  275                  s = "factory MAC address slots not supported";
 276  276                  break;
 277  277          case DLADM_STATUS_INVALIDMACPREFIX:
 278  278                  s = "Invalid MAC address prefix value";
 279  279                  break;
 280  280          case DLADM_STATUS_INVALIDMACPREFIXLEN:
 281  281                  s = "Invalid MAC address prefix length";
 282  282                  break;
 283  283          case DLADM_STATUS_BADCPUID:
 284  284                  s = "non-existent processor ID";
 285  285                  break;
 286  286          case DLADM_STATUS_CPUERR:
 287  287                  s = "could not determine processor status";
 288  288                  break;
 289  289          case DLADM_STATUS_CPUNOTONLINE:
 290  290                  s = "processor not online";
 291  291                  break;
 292  292          case DLADM_STATUS_TOOMANYELEMENTS:
 293  293                  s = "too many elements specified";
 294  294                  break;
 295  295          case DLADM_STATUS_BADRANGE:
 296  296                  s = "invalid range";
 297  297                  break;
 298  298          case DLADM_STATUS_DB_NOTFOUND:
 299  299                  s = "database not found";
 300  300                  break;
 301  301          case DLADM_STATUS_DB_PARSE_ERR:
 302  302                  s = "database parse error";
 303  303                  break;
 304  304          case DLADM_STATUS_PROP_PARSE_ERR:
 305  305                  s = "property parse error";
 306  306                  break;
 307  307          case DLADM_STATUS_ATTR_PARSE_ERR:
 308  308                  s = "attribute parse error";
 309  309                  break;
 310  310          case DLADM_STATUS_FLOW_DB_ERR:
 311  311                  s = "flow database error";
 312  312                  break;
 313  313          case DLADM_STATUS_FLOW_DB_OPEN_ERR:
 314  314                  s = "flow database open error";
 315  315                  break;
 316  316          case DLADM_STATUS_FLOW_DB_PARSE_ERR:
 317  317                  s = "flow database parse error";
 318  318                  break;
 319  319          case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR:
 320  320                  s = "flow property database parse error";
 321  321                  break;
 322  322          case DLADM_STATUS_FLOW_ADD_ERR:
 323  323                  s = "flow add error";
 324  324                  break;
 325  325          case DLADM_STATUS_FLOW_WALK_ERR:
 326  326                  s = "flow walk error";
 327  327                  break;
 328  328          case DLADM_STATUS_FLOW_IDENTICAL:
 329  329                  s = "a flow with identical attributes exists";
 330  330                  break;
 331  331          case DLADM_STATUS_FLOW_INCOMPATIBLE:
 332  332                  s = "flow(s) with incompatible attributes exists";
 333  333                  break;
 334  334          case DLADM_STATUS_FLOW_EXISTS:
 335  335                  s = "link still has flows";
 336  336                  break;
 337  337          case DLADM_STATUS_PERSIST_FLOW_EXISTS:
 338  338                  s = "persistent flow with the same name exists";
 339  339                  break;
 340  340          case DLADM_STATUS_INVALID_IP:
 341  341                  s = "invalid IP address";
 342  342                  break;
 343  343          case DLADM_STATUS_INVALID_PREFIXLEN:
 344  344                  s = "invalid IP prefix length";
 345  345                  break;
 346  346          case DLADM_STATUS_INVALID_PROTOCOL:
 347  347                  s = "invalid IP protocol";
 348  348                  break;
 349  349          case DLADM_STATUS_INVALID_PORT:
 350  350                  s = "invalid port number";
 351  351                  break;
 352  352          case DLADM_STATUS_INVALID_DSF:
 353  353                  s = "invalid dsfield";
 354  354                  break;
 355  355          case DLADM_STATUS_INVALID_DSFMASK:
 356  356                  s = "invalid dsfield mask";
 357  357                  break;
 358  358          case DLADM_STATUS_INVALID_MACMARGIN:
 359  359                  s = "MTU check failed, use lower MTU or -f option";
 360  360                  break;
 361  361          case DLADM_STATUS_BADPROP:
 362  362                  s = "invalid property";
 363  363                  break;
 364  364          case DLADM_STATUS_MINMAXBW:
 365  365                  s = "minimum value for maxbw is 1200K";
 366  366                  break;
 367  367          case DLADM_STATUS_NO_HWRINGS:
 368  368                  s = "request hw rings failed";
 369  369                  break;
 370  370          case DLADM_STATUS_PERMONLY:
 371  371                  s = "change must be persistent";
 372  372                  break;
 373  373          case DLADM_STATUS_OPTMISSING:
 374  374                  s = "optional software not installed";
 375  375                  break;
 376  376          case DLADM_STATUS_IPTUNTYPE:
 377  377                  s = "invalid IP tunnel type";
 378  378                  break;
 379  379          case DLADM_STATUS_IPTUNTYPEREQD:
 380  380                  s = "IP tunnel type required";
 381  381                  break;
 382  382          case DLADM_STATUS_BADIPTUNLADDR:
 383  383                  s = "invalid local IP tunnel address";
 384  384                  break;
 385  385          case DLADM_STATUS_BADIPTUNRADDR:
 386  386                  s = "invalid remote IP tunnel address";
 387  387                  break;
 388  388          case DLADM_STATUS_ADDRINUSE:
 389  389                  s = "address already in use";
 390  390                  break;
 391  391          case DLADM_STATUS_POOLCPU:
 392  392                  s = "pool and cpus property are mutually exclusive";
 393  393                  break;
 394  394          case DLADM_STATUS_INVALID_PORT_INSTANCE:
 395  395                  s = "invalid IB phys link";
 396  396                  break;
 397  397          case DLADM_STATUS_PORT_IS_DOWN:
 398  398                  s = "port is down";
 399  399                  break;
 400  400          case DLADM_STATUS_PARTITION_EXISTS:
 401  401                  s = "partition already exists";
 402  402                  break;
 403  403          case DLADM_STATUS_PKEY_NOT_PRESENT:
 404  404                  s = "PKEY is not present on the port";
 405  405                  break;
 406  406          case DLADM_STATUS_INVALID_PKEY:
 407  407                  s = "invalid PKEY";
 408  408                  break;
 409  409          case DLADM_STATUS_NO_IB_HW_RESOURCE:
 410  410                  s = "IB internal resource not available";
 411  411                  break;
 412  412          case DLADM_STATUS_INVALID_PKEY_TBL_SIZE:
 413  413                  s = "invalid PKEY table size";
 414  414                  break;
 415  415          case DLADM_STATUS_PORT_NOPROTO:
 416  416                  s = "local or remote port requires transport";
 417  417                  break;
 418  418          case DLADM_STATUS_INVALID_MTU:
 419  419                  s = "MTU check failed, MTU outside of device's supported range";
 420  420                  break;
 421  421          default:
 422  422                  s = "<unknown error>";
 423  423                  break;
 424  424          }
 425  425          (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
 426  426          return (buf);
 427  427  }
 428  428  
 429  429  /*
 430  430   * Convert a unix errno to a dladm_status_t.
 431  431   * We only convert errnos that are likely to be encountered. All others
 432  432   * are mapped to DLADM_STATUS_FAILED.
 433  433   */
 434  434  dladm_status_t
 435  435  dladm_errno2status(int err)
 436  436  {
 437  437          switch (err) {
 438  438          case 0:
 439  439                  return (DLADM_STATUS_OK);
 440  440          case EINVAL:
 441  441                  return (DLADM_STATUS_BADARG);
 442  442          case EEXIST:
 443  443                  return (DLADM_STATUS_EXIST);
 444  444          case ENOENT:
 445  445                  return (DLADM_STATUS_NOTFOUND);
 446  446          case ENOSPC:
 447  447                  return (DLADM_STATUS_TOOSMALL);
 448  448          case ENOMEM:
 449  449                  return (DLADM_STATUS_NOMEM);
 450  450          case ENOTSUP:
 451  451                  return (DLADM_STATUS_NOTSUP);
 452  452          case ENETDOWN:
 453  453                  return (DLADM_STATUS_NONOTIF);
 454  454          case EACCES:
 455  455          case EPERM:
 456  456                  return (DLADM_STATUS_DENIED);
 457  457          case EIO:
 458  458                  return (DLADM_STATUS_IOERR);
 459  459          case EBUSY:
 460  460                  return (DLADM_STATUS_LINKBUSY);
 461  461          case EAGAIN:
 462  462                  return (DLADM_STATUS_TRYAGAIN);
 463  463          case ENOTEMPTY:
 464  464                  return (DLADM_STATUS_FLOW_EXISTS);
 465  465          case EOPNOTSUPP:
 466  466                  return (DLADM_STATUS_FLOW_INCOMPATIBLE);
 467  467          case EALREADY:
 468  468                  return (DLADM_STATUS_FLOW_IDENTICAL);
 469  469          case EADDRINUSE:
 470  470                  return (DLADM_STATUS_ADDRINUSE);
 471  471          default:
 472  472                  return (DLADM_STATUS_FAILED);
 473  473          }
 474  474  }
 475  475  
 476  476  boolean_t
 477  477  dladm_str2interval(char *oarg, uint32_t *interval)
 478  478  {
 479  479          int             val;
 480  480          char            *endp = NULL;
 481  481  
 482  482          errno = 0;
 483  483          val = strtol(oarg, &endp, 10);
 484  484          if (errno != 0 || val <= 0 || *endp != '\0')
 485  485                  return (B_FALSE);
 486  486  
 487  487          *interval = val;
 488  488  
  
    | 
      ↓ open down ↓ | 
    488 lines elided | 
    
      ↑ open up ↑ | 
  
 489  489          return (B_TRUE);
 490  490  }
 491  491  
 492  492  dladm_status_t
 493  493  dladm_str2bw(char *oarg, uint64_t *bw)
 494  494  {
 495  495          char            *endp = NULL;
 496  496          int64_t         n;
 497  497          int             mult = 1;
 498  498  
      499 +        errno = 0;
 499  500          n = strtoull(oarg, &endp, 10);
 500  501  
 501  502          if ((errno != 0) || (strlen(endp) > 1))
 502  503                  return (DLADM_STATUS_BADARG);
 503  504  
 504  505          if (n < 0)
 505  506                  return (DLADM_STATUS_BADVAL);
 506  507  
 507  508          switch (*endp) {
 508  509          case 'k':
 509  510          case 'K':
 510  511                  mult = 1000;
 511  512                  break;
 512  513          case 'm':
 513  514          case 'M':
 514  515          case '\0':
 515  516                  mult = 1000000;
 516  517                  break;
 517  518          case 'g':
 518  519          case 'G':
 519  520                  mult = 1000000000;
 520  521                  break;
 521  522          case '%':
 522  523                  /*
 523  524                   * percentages not supported for now,
 524  525                   * see RFE 6540675
 525  526                   */
 526  527                  return (DLADM_STATUS_NOTSUP);
 527  528          default:
 528  529                  return (DLADM_STATUS_BADVAL);
 529  530          }
 530  531  
 531  532          *bw = n * mult;
 532  533  
 533  534          /* check for overflow */
 534  535          if (*bw / mult != n)
 535  536                  return (DLADM_STATUS_BADARG);
 536  537  
 537  538          return (DLADM_STATUS_OK);
 538  539  }
 539  540  
 540  541  /*
 541  542   * Convert bandwidth in bps to a string in Mbps.  For values greater
 542  543   * than 1Mbps or 1000000, print a whole Mbps value.  For values that
 543  544   * have fractional Mbps in whole Kbps, print the bandwidth in a manner
 544  545   * similar to a floating point format.
 545  546   *
 546  547   *        bps       string
 547  548   *          0            0
 548  549   *        100            0
 549  550   *       2000        0.002
 550  551   *     431000        0.431
 551  552   *    1000000            1
 552  553   *    1030000        1.030
 553  554   *  100000000          100
 554  555   */
 555  556  const char *
 556  557  dladm_bw2str(int64_t bw, char *buf)
 557  558  {
 558  559          int kbps, mbps;
 559  560  
 560  561          kbps = (bw%1000000)/1000;
 561  562          mbps = bw/1000000;
 562  563          if (kbps != 0) {
 563  564                  if (mbps == 0)
 564  565                          (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps);
 565  566                  else
 566  567                          (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps,
 567  568                              kbps);
 568  569          } else {
 569  570                  (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps);
 570  571          }
 571  572  
 572  573          return (buf);
 573  574  }
 574  575  
 575  576  #define LOCK_DB_PERMS   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
 576  577  
 577  578  static int
 578  579  i_dladm_lock_db(const char *lock_file, short type)
 579  580  {
 580  581          int     lock_fd;
 581  582          struct  flock lock;
 582  583  
 583  584          if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
 584  585              LOCK_DB_PERMS)) < 0)
 585  586                  return (-1);
 586  587  
 587  588          lock.l_type = type;
 588  589          lock.l_whence = SEEK_SET;
 589  590          lock.l_start = 0;
 590  591          lock.l_len = 0;
 591  592  
 592  593          if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
 593  594                  int err = errno;
 594  595  
 595  596                  (void) close(lock_fd);
 596  597                  (void) unlink(lock_file);
 597  598                  errno = err;
 598  599                  return (-1);
 599  600          }
 600  601          return (lock_fd);
 601  602  }
 602  603  
 603  604  static void
 604  605  i_dladm_unlock_db(const char *lock_file, int fd)
 605  606  {
 606  607          struct flock lock;
 607  608  
 608  609          if (fd < 0)
 609  610                  return;
 610  611  
 611  612          lock.l_type = F_UNLCK;
 612  613          lock.l_whence = SEEK_SET;
 613  614          lock.l_start = 0;
 614  615          lock.l_len = 0;
 615  616  
 616  617          (void) fcntl(fd, F_SETLKW, &lock);
 617  618          (void) close(fd);
 618  619          (void) unlink(lock_file);
 619  620  }
 620  621  
 621  622  /*
 622  623   * Given a link class, returns its class string.
 623  624   */
 624  625  const char *
 625  626  dladm_class2str(datalink_class_t class, char *buf)
 626  627  {
 627  628          const char *s;
 628  629  
 629  630          switch (class) {
 630  631          case DATALINK_CLASS_PHYS:
 631  632                  s = "phys";
 632  633                  break;
 633  634          case DATALINK_CLASS_VLAN:
 634  635                  s = "vlan";
 635  636                  break;
 636  637          case DATALINK_CLASS_AGGR:
 637  638                  s = "aggr";
 638  639                  break;
 639  640          case DATALINK_CLASS_VNIC:
 640  641                  s = "vnic";
 641  642                  break;
 642  643          case DATALINK_CLASS_ETHERSTUB:
 643  644                  s = "etherstub";
 644  645                  break;
 645  646          case DATALINK_CLASS_IPTUN:
 646  647                  s = "iptun";
 647  648                  break;
 648  649          case DATALINK_CLASS_SIMNET:
 649  650                  s = "simnet";
 650  651                  break;
 651  652          case DATALINK_CLASS_BRIDGE:
 652  653                  s = "bridge";
 653  654                  break;
 654  655          case DATALINK_CLASS_PART:
 655  656                  s = "part";
 656  657                  break;
 657  658          default:
 658  659                  s = "unknown";
 659  660                  break;
 660  661          }
 661  662  
 662  663          (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
 663  664          return (buf);
 664  665  }
 665  666  
 666  667  /*
 667  668   * Given a physical link media type, returns its media type string.
 668  669   */
 669  670  const char *
 670  671  dladm_media2str(uint32_t media, char *buf)
 671  672  {
 672  673          const char *s = "--";
 673  674          media_type_t *mt;
 674  675          int idx;
 675  676  
 676  677          for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
 677  678                  mt = media_type_table + idx;
 678  679                  if (mt->media_type == media) {
 679  680                          s = mt->media_type_str;
 680  681                          break;
 681  682                  }
 682  683          }
 683  684  
 684  685          (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
 685  686          return (buf);
 686  687  }
 687  688  
 688  689  /*
 689  690   * Given a physical link media type string, returns its media type constant.
 690  691   */
 691  692  uint32_t
 692  693  dladm_str2media(const char *buf)
 693  694  {
 694  695          media_type_t *mt;
 695  696          int idx;
 696  697  
 697  698          for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
 698  699                  mt = media_type_table + idx;
 699  700                  if (strcasecmp(buf, mt->media_type_str) == 0)
 700  701                          return (mt->media_type);
 701  702          }
 702  703  
 703  704          return (DL_OTHER);
 704  705  }
 705  706  
 706  707  dladm_status_t
 707  708  i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms,
 708  709      dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *),
 709  710      void *arg, boolean_t writeop)
 710  711  {
 711  712          dladm_status_t  status = DLADM_STATUS_OK;
 712  713          FILE            *fp, *nfp = NULL;
 713  714          char            lock[MAXPATHLEN];
 714  715          char            file[MAXPATHLEN];
 715  716          char            newfile[MAXPATHLEN];
 716  717          char            *db_basename;
 717  718          int             nfd, lock_fd;
 718  719  
 719  720          /*
 720  721           * If we are called from a boot script such as net-physical,
 721  722           * it's quite likely that the root fs is still not writable.
 722  723           * For this case, it's ok for the lock creation to fail since
 723  724           * no one else could be accessing our configuration file.
 724  725           */
 725  726          db_basename = strrchr(db_file, '/');
 726  727          if (db_basename == NULL || db_basename[1] == '\0')
 727  728                  return (dladm_errno2status(EINVAL));
 728  729          db_basename++;
 729  730          (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
 730  731          if ((lock_fd = i_dladm_lock_db
 731  732              (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
 732  733                  return (dladm_errno2status(errno));
 733  734  
 734  735          (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
 735  736          if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
 736  737                  int     err = errno;
 737  738  
 738  739                  i_dladm_unlock_db(lock, lock_fd);
 739  740                  if (err == ENOENT)
 740  741                          return (DLADM_STATUS_DBNOTFOUND);
 741  742  
 742  743                  return (dladm_errno2status(err));
 743  744          }
 744  745  
 745  746          if (writeop) {
 746  747                  (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
 747  748                      dladm_rootdir, db_file);
 748  749                  if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
 749  750                      db_perms)) < 0) {
 750  751                          (void) fclose(fp);
 751  752                          i_dladm_unlock_db(lock, lock_fd);
 752  753                          return (dladm_errno2status(errno));
 753  754                  }
 754  755  
 755  756                  if ((nfp = fdopen(nfd, "w")) == NULL) {
 756  757                          (void) close(nfd);
 757  758                          (void) fclose(fp);
 758  759                          (void) unlink(newfile);
 759  760                          i_dladm_unlock_db(lock, lock_fd);
 760  761                          return (dladm_errno2status(errno));
 761  762                  }
 762  763          }
 763  764          status = (*process_db)(handle, arg, fp, nfp);
 764  765          if (!writeop || status != DLADM_STATUS_OK)
 765  766                  goto done;
 766  767  
 767  768          /* Set permissions on file to db_perms */
 768  769          if (fchmod(nfd, db_perms) < 0) {
 769  770                  status = dladm_errno2status(errno);
 770  771                  goto done;
 771  772          }
 772  773  
 773  774          /*
 774  775           * Configuration files need to be owned by the 'dladm' user and
 775  776           * 'netadm' group.
 776  777           */
 777  778          if (fchown(nfd, UID_DLADM, GID_NETADM) < 0) {
 778  779                  status = dladm_errno2status(errno);
 779  780                  goto done;
 780  781          }
 781  782  
 782  783          if (fflush(nfp) == EOF) {
 783  784                  status = dladm_errno2status(errno);
 784  785                  goto done;
 785  786          }
 786  787          (void) fclose(fp);
 787  788          (void) fclose(nfp);
 788  789  
 789  790          if (rename(newfile, file) < 0) {
 790  791                  (void) unlink(newfile);
 791  792                  i_dladm_unlock_db(lock, lock_fd);
 792  793                  return (dladm_errno2status(errno));
 793  794          }
 794  795  
 795  796          i_dladm_unlock_db(lock, lock_fd);
 796  797          return (DLADM_STATUS_OK);
 797  798  
 798  799  done:
 799  800          if (nfp != NULL) {
 800  801                  (void) fclose(nfp);
 801  802                  if (status != DLADM_STATUS_OK)
 802  803                          (void) unlink(newfile);
 803  804          }
 804  805          (void) fclose(fp);
 805  806          i_dladm_unlock_db(lock, lock_fd);
 806  807          return (status);
 807  808  }
 808  809  
 809  810  dladm_status_t
 810  811  dladm_set_rootdir(const char *rootdir)
 811  812  {
 812  813          DIR     *dp;
 813  814  
 814  815          if (rootdir == NULL || *rootdir != '/' ||
 815  816              (dp = opendir(rootdir)) == NULL)
 816  817                  return (DLADM_STATUS_BADARG);
 817  818  
 818  819          (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
 819  820          (void) closedir(dp);
 820  821          return (DLADM_STATUS_OK);
 821  822  }
 822  823  
 823  824  boolean_t
 824  825  dladm_valid_linkname(const char *link)
 825  826  {
 826  827          size_t          len = strlen(link);
 827  828          const char      *cp;
 828  829          int             nd = 0;
 829  830  
 830  831          if (len >= MAXLINKNAMELEN)
 831  832                  return (B_FALSE);
 832  833  
 833  834          /* Link name cannot start with a digit */
 834  835          if (isdigit(link[0]))
 835  836                  return (B_FALSE);
 836  837          /* Link name must end with a number without leading zeroes */
 837  838          cp = link + len - 1;
 838  839          while (isdigit(*cp)) {
 839  840                  cp--;
 840  841                  nd++;
 841  842          }
 842  843          if (nd == 0 || (nd > 1 && *(cp + 1) == '0'))
 843  844                  return (B_FALSE);
 844  845  
 845  846          /*
 846  847           * The legal characters in a link name are:
 847  848           * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
 848  849           */
 849  850          for (cp = link; *cp != '\0'; cp++) {
 850  851                  if ((isalnum(*cp) == 0) && (*cp != '_') && (*cp != '.'))
 851  852                          return (B_FALSE);
 852  853          }
 853  854  
 854  855          return (B_TRUE);
 855  856  }
 856  857  
 857  858  /*
 858  859   * Convert priority string to a value.
 859  860   */
 860  861  dladm_status_t
 861  862  dladm_str2pri(char *token, mac_priority_level_t *pri)
 862  863  {
 863  864          if (strlen(token) == strlen("low") &&
 864  865              strncasecmp(token, "low", strlen("low")) == 0) {
 865  866                  *pri = MPL_LOW;
 866  867          } else if (strlen(token) == strlen("medium") &&
 867  868              strncasecmp(token, "medium", strlen("medium")) == 0) {
 868  869                  *pri = MPL_MEDIUM;
 869  870          } else if (strlen(token) == strlen("high") &&
 870  871              strncasecmp(token, "high", strlen("high")) == 0) {
 871  872                  *pri = MPL_HIGH;
 872  873          } else {
 873  874                  return (DLADM_STATUS_BADVAL);
 874  875          }
 875  876          return (DLADM_STATUS_OK);
 876  877  }
 877  878  
 878  879  /*
 879  880   * Convert priority value to a string.
 880  881   */
 881  882  const char *
 882  883  dladm_pri2str(mac_priority_level_t pri, char *buf)
 883  884  {
 884  885          const char      *s;
 885  886  
 886  887          switch (pri) {
 887  888          case MPL_LOW:
 888  889                  s = "low";
 889  890                  break;
 890  891          case MPL_MEDIUM:
 891  892                  s = "medium";
 892  893                  break;
 893  894          case MPL_HIGH:
 894  895                  s = "high";
 895  896                  break;
 896  897          default:
 897  898                  s = "--";
 898  899                  break;
 899  900          }
 900  901          (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
 901  902          return (buf);
 902  903  }
 903  904  
 904  905  /*
 905  906   * Convert protect string to a value.
 906  907   */
 907  908  dladm_status_t
 908  909  dladm_str2protect(char *token, uint32_t *ptype)
 909  910  {
 910  911          link_protect_t  *lp;
 911  912          int             i;
 912  913  
 913  914          for (i = 0; i < LPTYPES; i++) {
 914  915                  lp = &link_protect_types[i];
 915  916                  if (strcmp(token, lp->lp_name) == 0) {
 916  917                          *ptype = lp->lp_type;
 917  918                          return (DLADM_STATUS_OK);
 918  919                  }
 919  920          }
 920  921          return (DLADM_STATUS_BADVAL);
 921  922  }
 922  923  
 923  924  /*
 924  925   * Convert protect value to a string.
 925  926   */
 926  927  const char *
 927  928  dladm_protect2str(uint32_t ptype, char *buf)
 928  929  {
 929  930          const char      *s = "--";
 930  931          link_protect_t  *lp;
 931  932          int             i;
 932  933  
 933  934          for (i = 0; i < LPTYPES; i++) {
 934  935                  lp = &link_protect_types[i];
 935  936                  if (lp->lp_type == ptype) {
 936  937                          s = lp->lp_name;
 937  938                          break;
 938  939                  }
 939  940          }
 940  941          (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
 941  942          return (buf);
 942  943  }
 943  944  
 944  945  /*
 945  946   * Convert an IPv4 address to/from a string.
 946  947   */
 947  948  const char *
 948  949  dladm_ipv4addr2str(void *addr, char *buf)
 949  950  {
 950  951          if (inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN) == NULL)
 951  952                  buf[0] = '\0';
 952  953  
 953  954          return (buf);
 954  955  }
 955  956  
 956  957  dladm_status_t
 957  958  dladm_str2ipv4addr(char *token, void *addr)
 958  959  {
 959  960          return (inet_pton(AF_INET, token, addr) == 1 ?
 960  961              DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP);
 961  962  }
 962  963  
 963  964  const char *
 964  965  dladm_ipv6addr2str(void *addr, char *buf)
 965  966  {
 966  967          if (inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN) == NULL)
 967  968                  buf[0] = '\0';
 968  969  
 969  970          return (buf);
 970  971  }
 971  972  
 972  973  dladm_status_t
 973  974  dladm_str2ipv6addr(char *token, void *addr)
 974  975  {
 975  976          return (inet_pton(AF_INET6, token, addr) == 1 ?
 976  977              DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP);
 977  978  }
 978  979  
 979  980  /*
 980  981   * Find the set bits in a mask.
 981  982   * This is used for expanding a bitmask into individual sub-masks
 982  983   * which can be used for further processing.
 983  984   */
 984  985  void
 985  986  dladm_find_setbits32(uint32_t mask, uint32_t *list, uint32_t *cnt)
 986  987  {
 987  988          int     i, c = 0;
 988  989  
 989  990          for (i = 0; i < 32; i++) {
 990  991                  if (((1 << i) & mask) != 0)
 991  992                          list[c++] = 1 << i;
 992  993          }
 993  994          *cnt = c;
 994  995  }
 995  996  
 996  997  void
 997  998  dladm_free_args(dladm_arg_list_t *list)
 998  999  {
 999 1000          if (list != NULL) {
1000 1001                  free(list->al_buf);
1001 1002                  free(list);
1002 1003          }
1003 1004  }
1004 1005  
1005 1006  dladm_status_t
1006 1007  dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues)
1007 1008  {
1008 1009          dladm_arg_list_t        *list;
1009 1010          dladm_arg_info_t        *aip;
1010 1011          char                    *buf, *curr;
1011 1012          int                     len, i;
1012 1013  
1013 1014          if (str == NULL)
1014 1015                  return (DLADM_STATUS_BADVAL);
1015 1016  
1016 1017          if (str[0] == '\0')
1017 1018                  return (DLADM_STATUS_OK);
1018 1019  
1019 1020          list = malloc(sizeof (dladm_arg_list_t));
1020 1021          if (list == NULL)
1021 1022                  return (dladm_errno2status(errno));
1022 1023  
1023 1024          list->al_count = 0;
1024 1025          list->al_buf = buf = strdup(str);
1025 1026          if (buf == NULL)
1026 1027                  return (dladm_errno2status(errno));
1027 1028  
1028 1029          curr = buf;
1029 1030          len = strlen(buf);
1030 1031          aip = NULL;
1031 1032          for (i = 0; i < len; i++) {
1032 1033                  char            c = buf[i];
1033 1034                  boolean_t       match = (c == '=' || c == ',');
1034 1035  
1035 1036                  if (!match && i != len - 1)
1036 1037                          continue;
1037 1038  
1038 1039                  if (match) {
1039 1040                          buf[i] = '\0';
1040 1041                          if (*curr == '\0')
1041 1042                                  goto fail;
1042 1043                  }
1043 1044  
1044 1045                  if (aip != NULL && c != '=') {
1045 1046                          if (aip->ai_count > DLADM_MAX_ARG_VALS)
1046 1047                                  goto fail;
1047 1048  
1048 1049                          if (novalues)
1049 1050                                  goto fail;
1050 1051  
1051 1052                          aip->ai_val[aip->ai_count] = curr;
1052 1053                          aip->ai_count++;
1053 1054                  } else {
1054 1055                          if (list->al_count > DLADM_MAX_ARG_VALS)
1055 1056                                  goto fail;
1056 1057  
1057 1058                          aip = &list->al_info[list->al_count];
1058 1059                          aip->ai_name = curr;
1059 1060                          aip->ai_count = 0;
1060 1061                          list->al_count++;
1061 1062                          if (c == ',')
1062 1063                                  aip = NULL;
1063 1064                  }
1064 1065                  curr = buf + i + 1;
1065 1066          }
1066 1067  
1067 1068          *listp = list;
1068 1069          return (DLADM_STATUS_OK);
1069 1070  
1070 1071  fail:
1071 1072          dladm_free_args(list);
1072 1073          return (DLADM_STATUS_FAILED);
1073 1074  }
1074 1075  
1075 1076  /*
1076 1077   * mac_propval_range_t functions.  Currently implemented for only
1077 1078   * ranges of uint32_t elements, but can be expanded as required.
1078 1079   */
1079 1080  /*
1080 1081   * Convert an array of strings (which can be ranges or individual
1081 1082   * elements) into a single mac_propval_range_t structure which
1082 1083   * is allocated here but should be freed by the caller.
1083 1084   */
1084 1085  dladm_status_t
1085 1086  dladm_strs2range(char **prop_val, uint_t val_cnt, mac_propval_type_t type,
1086 1087      mac_propval_range_t **range)
1087 1088  {
1088 1089          int                     i;
1089 1090          char                    *endp;
1090 1091          mac_propval_range_t     *rangep;
1091 1092          dladm_status_t          status = DLADM_STATUS_OK;
1092 1093  
1093 1094          switch (type) {
1094 1095          case MAC_PROPVAL_UINT32: {
1095 1096                  mac_propval_uint32_range_t      *ur;
1096 1097  
1097 1098                  /* Allocate range structure */
1098 1099                  rangep = malloc(sizeof (mac_propval_range_t) +
1099 1100                      (val_cnt-1)*(sizeof (mac_propval_uint32_range_t)));
1100 1101                  if (rangep == NULL)
1101 1102                          return (DLADM_STATUS_NOMEM);
1102 1103  
1103 1104                  rangep->mpr_count = 0;
1104 1105                  ur = &rangep->mpr_range_uint32[0];
1105 1106                  for (i = 0; i < val_cnt; i++, ur++) {
1106 1107                          errno = 0;
1107 1108                          if (strchr(prop_val[i], '-') == NULL) {
1108 1109                                  /* single element */
1109 1110                                  ur->mpur_min = ur->mpur_max =
1110 1111                                      strtol(prop_val[i], &endp, 10);
1111 1112                                  if ((endp != NULL) && (*endp != '\0')) {
1112 1113                                          return (DLADM_STATUS_BADRANGE);
1113 1114                                  }
1114 1115                          } else {
1115 1116                                  /* range of elements */
1116 1117                                  ur->mpur_min = strtol(prop_val[i], &endp, 10);
1117 1118                                  if (*endp++ != '-')
1118 1119                                          return (DLADM_STATUS_BADRANGE);
1119 1120                                  ur->mpur_max = strtol(endp, &endp, 10);
1120 1121                                  if (endp != NULL && *endp != '\0' ||
1121 1122                                      ur->mpur_max < ur->mpur_min)
1122 1123                                          return (DLADM_STATUS_BADRANGE);
1123 1124                          }
1124 1125                          rangep->mpr_count++;
1125 1126                  }
1126 1127                  break;
1127 1128          }
1128 1129          default:
1129 1130                  return (DLADM_STATUS_BADVAL);
1130 1131          }
1131 1132  
1132 1133          rangep->mpr_type = type;
1133 1134          *range = rangep;
1134 1135  
1135 1136          return (status);
1136 1137  }
1137 1138  
1138 1139  /*
1139 1140   * Convert a mac_propval_range_t structure into an array of elements.
1140 1141   */
1141 1142  dladm_status_t
1142 1143  dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem)
1143 1144  {
1144 1145          int             i, j, k;
1145 1146          dladm_status_t  status = DLADM_STATUS_OK;
1146 1147  
1147 1148          switch (rangep->mpr_type) {
1148 1149          case MAC_PROPVAL_UINT32: {
1149 1150                  mac_propval_uint32_range_t      *ur;
1150 1151                  uint32_t                        *elem32 = elem;
1151 1152  
1152 1153                  k = 0;
1153 1154                  ur = &rangep->mpr_range_uint32[0];
1154 1155                  for (i = 0; i < rangep->mpr_count; i++, ur++) {
1155 1156                          for (j = 0; j <= ur->mpur_max - ur->mpur_min; j++) {
1156 1157                                  elem32[k++] = ur->mpur_min + j;
1157 1158                                  if (k > *nelem) {
1158 1159                                          status = DLADM_STATUS_TOOMANYELEMENTS;
1159 1160                                          break;
1160 1161                                  }
1161 1162                          }
1162 1163                  }
1163 1164                  *nelem = k;
1164 1165                  break;
1165 1166          }
1166 1167          default:
1167 1168                  status = DLADM_STATUS_BADVAL;
1168 1169                  break;
1169 1170          }
1170 1171          return (status);
1171 1172  }
1172 1173  
1173 1174  /*
1174 1175   * Convert a mac_propval_range_t structure into an array of strings
1175 1176   * of single elements or ranges.
1176 1177   */
1177 1178  int
1178 1179  dladm_range2strs(mac_propval_range_t *rangep, char **prop_val)
1179 1180  {
1180 1181          int     i;
1181 1182  
1182 1183          switch (rangep->mpr_type) {
1183 1184          case MAC_PROPVAL_UINT32: {
1184 1185                  mac_propval_uint32_range_t      *ur;
1185 1186  
1186 1187                  /* Write ranges and individual elements */
1187 1188                  ur = &rangep->mpr_range_uint32[0];
1188 1189                  for (i = 0; i < rangep->mpr_count; i++, ur++) {
1189 1190                          if (ur->mpur_min == ur->mpur_max) {
1190 1191                                  /* single element */
1191 1192                                  (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1192 1193                                      "%u", ur->mpur_min);
1193 1194                          } else {
1194 1195                                  /* range of elements */
1195 1196                                  (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1196 1197                                      "%u-%u", ur->mpur_min, ur->mpur_max);
1197 1198                          }
1198 1199                  }
1199 1200                  return (0);
1200 1201          }
1201 1202          default:
1202 1203                  break;
1203 1204          }
1204 1205          return (EINVAL);
1205 1206  }
1206 1207  
1207 1208  static int
1208 1209  uint32cmp(const void *a, const void *b)
1209 1210  {
1210 1211          return (*(uint32_t *)a - *(uint32_t *)b);
1211 1212  }
1212 1213  
1213 1214  /*
1214 1215   * Sort and convert an array of elements into a single
1215 1216   * mac_propval_range_t structure which is allocated here but
1216 1217   * should be freed by the caller.
1217 1218   */
1218 1219  dladm_status_t
1219 1220  dladm_list2range(void *elem, uint_t nelem, mac_propval_type_t type,
1220 1221      mac_propval_range_t **range)
1221 1222  {
1222 1223          int                     i;
1223 1224          uint_t                  nr = 0;
1224 1225          mac_propval_range_t     *rangep;
1225 1226          dladm_status_t          status = DLADM_STATUS_OK;
1226 1227  
1227 1228          switch (type) {
1228 1229          case MAC_PROPVAL_UINT32: {
1229 1230                  mac_propval_uint32_range_t      *ur;
1230 1231                  uint32_t                        *elem32 = elem;
1231 1232                  uint32_t                        *sort32;
1232 1233  
1233 1234                  /* Allocate range structure */
1234 1235                  rangep = malloc(sizeof (mac_propval_range_t) +
1235 1236                      (nelem-1)*(sizeof (mac_propval_uint32_range_t)));
1236 1237                  if (rangep == NULL)
1237 1238                          return (DLADM_STATUS_NOMEM);
1238 1239  
1239 1240                  /* Allocate array for sorting */
1240 1241                  sort32 = malloc(nelem * sizeof (uint32_t));
1241 1242                  if (sort32 == NULL) {
1242 1243                          free(rangep);
1243 1244                          return (DLADM_STATUS_NOMEM);
1244 1245                  }
1245 1246  
1246 1247                  /* Copy and sort list */
1247 1248                  for (i = 0; i < nelem; i++)
1248 1249                          sort32[i] =  elem32[i];
1249 1250                  if (nelem > 1)
1250 1251                          qsort(sort32, nelem, sizeof (uint32_t), uint32cmp);
1251 1252  
1252 1253                  /* Convert list to ranges */
1253 1254                  ur = &rangep->mpr_range_uint32[0];
1254 1255                  ur->mpur_min = ur->mpur_max = sort32[0];
1255 1256                  for (i = 1; i < nelem; i++) {
1256 1257                          if (sort32[i]-sort32[i-1] == 1) {
1257 1258                                  /* part of current range */
1258 1259                                  ur->mpur_max = sort32[i];
1259 1260                          } else {
1260 1261                                  /* start a new range */
1261 1262                                  nr++; ur++;
1262 1263                                  ur->mpur_min = ur->mpur_max = sort32[i];
1263 1264                          }
1264 1265                  }
1265 1266                  free(sort32);
1266 1267                  break;
1267 1268          }
1268 1269          default:
1269 1270                  return (DLADM_STATUS_BADRANGE);
1270 1271          }
1271 1272  
1272 1273          rangep->mpr_type = type;
1273 1274          rangep->mpr_count = nr + 1;
1274 1275          *range = rangep;
1275 1276  
1276 1277          return (status);
1277 1278  }
  
    | 
      ↓ open down ↓ | 
    769 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX