4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/param.h>
37 #include <sys/dld_ioc.h>
38 #include <libdladm_impl.h>
41 #include <libdllink.h>
43 static char dladm_rootdir
[MAXPATHLEN
] = "/";
45 typedef struct media_type_desc
{
47 #define MAX_MEDIA_TYPE_STRING 32
48 const char media_type_str
[MAX_MEDIA_TYPE_STRING
];
51 static media_type_t media_type_table
[] = {
52 { DL_ETHER
, "Ethernet" },
54 { DL_IB
, "Infiniband" },
55 { DL_IPV4
, "IPv4Tunnel" },
56 { DL_IPV6
, "IPv6Tunnel" },
57 { DL_6TO4
, "6to4Tunnel" },
58 { DL_CSMACD
, "CSMA/CD" },
59 { DL_TPB
, "TokenBus" },
60 { DL_TPR
, "TokenRing" },
61 { DL_METRO
, "MetroNet" },
63 { DL_CHAR
, "SyncCharacter" },
66 { DL_FC
, "FiberChannel" },
68 { DL_IPATM
, "ATM(ClassicIP)" },
70 { DL_IPX25
, "X.25(ClassicIP)" },
72 { DL_HIPPI
, "HIPPI" },
73 { DL_100VG
, "100BaseVGEthernet" },
74 { DL_100VGTPR
, "100BaseVGTokenRing" },
75 { DL_ETH_CSMA
, "IEEE802.3" },
76 { DL_100BT
, "100BaseT" },
77 { DL_FRAME
, "FrameRelay" },
78 { DL_MPFRAME
, "MPFrameRelay" },
79 { DL_ASYNC
, "AsyncCharacter" },
80 { DL_IPNET
, "IPNET" },
83 #define MEDIATYPECOUNT (sizeof (media_type_table) / sizeof (media_type_t))
90 static link_protect_t link_protect_types
[] = {
91 { MPT_MACNOSPOOF
, "mac-nospoof" },
92 { MPT_RESTRICTED
, "restricted" },
93 { MPT_IPNOSPOOF
, "ip-nospoof" },
94 { MPT_DHCPNOSPOOF
, "dhcp-nospoof" }
96 #define LPTYPES (sizeof (link_protect_types) / sizeof (link_protect_t))
99 dladm_open(dladm_handle_t
*handle
)
104 return (DLADM_STATUS_BADARG
);
106 if ((dld_fd
= open(DLD_CONTROL_DEV
, O_RDWR
)) < 0)
107 return (dladm_errno2status(errno
));
110 * Don't open DLMGMT_DOOR now. dlmgmtd(1M) is not able to
111 * open the door when the dladm handle is opened because the
112 * door hasn't been created yet at that time. Thus, we must
113 * open it on-demand in dladm_door_fd(). Move the open()
114 * to dladm_door_fd() for all cases.
117 if ((*handle
= malloc(sizeof (struct dladm_handle
))) == NULL
) {
118 (void) close(dld_fd
);
119 return (DLADM_STATUS_NOMEM
);
122 (*handle
)->dld_fd
= dld_fd
;
123 (*handle
)->door_fd
= -1;
125 return (DLADM_STATUS_OK
);
129 dladm_close(dladm_handle_t handle
)
131 if (handle
!= NULL
) {
132 (void) close(handle
->dld_fd
);
133 if (handle
->door_fd
!= -1)
134 (void) close(handle
->door_fd
);
140 dladm_dld_fd(dladm_handle_t handle
)
142 return (handle
->dld_fd
);
146 * If DLMGMT_DOOR hasn't been opened in the handle yet, open it.
149 dladm_door_fd(dladm_handle_t handle
, int *door_fd
)
153 if (handle
->door_fd
== -1) {
154 if ((fd
= open(DLMGMT_DOOR
, O_RDONLY
)) < 0)
155 return (dladm_errno2status(errno
));
156 handle
->door_fd
= fd
;
158 *door_fd
= handle
->door_fd
;
160 return (DLADM_STATUS_OK
);
164 dladm_status2str(dladm_status_t status
, char *buf
)
169 case DLADM_STATUS_OK
:
172 case DLADM_STATUS_BADARG
:
173 s
= "invalid argument";
175 case DLADM_STATUS_FAILED
:
176 s
= "operation failed";
178 case DLADM_STATUS_TOOSMALL
:
179 s
= "buffer size too small";
181 case DLADM_STATUS_NOTSUP
:
182 s
= "operation not supported";
184 case DLADM_STATUS_NOTFOUND
:
185 s
= "object not found";
187 case DLADM_STATUS_BADVAL
:
190 case DLADM_STATUS_NOMEM
:
191 s
= "insufficient memory";
193 case DLADM_STATUS_EXIST
:
194 s
= "object already exists";
196 case DLADM_STATUS_LINKINVAL
:
199 case DLADM_STATUS_PROPRDONLY
:
200 s
= "read-only property";
202 case DLADM_STATUS_BADVALCNT
:
203 s
= "invalid number of values";
205 case DLADM_STATUS_DBNOTFOUND
:
206 s
= "database not found";
208 case DLADM_STATUS_DENIED
:
209 s
= "permission denied";
211 case DLADM_STATUS_IOERR
:
214 case DLADM_STATUS_TEMPONLY
:
215 s
= "change cannot be persistent";
217 case DLADM_STATUS_TIMEDOUT
:
218 s
= "operation timed out";
220 case DLADM_STATUS_ISCONN
:
221 s
= "already connected";
223 case DLADM_STATUS_NOTCONN
:
226 case DLADM_STATUS_REPOSITORYINVAL
:
227 s
= "invalid configuration repository";
229 case DLADM_STATUS_MACADDRINVAL
:
230 s
= "invalid MAC address";
232 case DLADM_STATUS_KEYINVAL
:
235 case DLADM_STATUS_INVALIDMACADDRLEN
:
236 s
= "invalid MAC address length";
238 case DLADM_STATUS_INVALIDMACADDRTYPE
:
239 s
= "invalid MAC address type";
241 case DLADM_STATUS_LINKBUSY
:
244 case DLADM_STATUS_VIDINVAL
:
245 s
= "invalid VLAN identifier";
247 case DLADM_STATUS_TRYAGAIN
:
248 s
= "try again later";
250 case DLADM_STATUS_NONOTIF
:
251 s
= "link notification is not supported";
253 case DLADM_STATUS_BADTIMEVAL
:
254 s
= "invalid time range";
256 case DLADM_STATUS_INVALIDMACADDR
:
257 s
= "invalid MAC address value";
259 case DLADM_STATUS_INVALIDMACADDRNIC
:
260 s
= "MAC address reserved for use by underlying data-link";
262 case DLADM_STATUS_INVALIDMACADDRINUSE
:
263 s
= "MAC address is already in use";
265 case DLADM_STATUS_MACFACTORYSLOTINVALID
:
266 s
= "invalid factory MAC address slot";
268 case DLADM_STATUS_MACFACTORYSLOTUSED
:
269 s
= "factory MAC address slot already used";
271 case DLADM_STATUS_MACFACTORYSLOTALLUSED
:
272 s
= "all factory MAC address slots are in use";
274 case DLADM_STATUS_MACFACTORYNOTSUP
:
275 s
= "factory MAC address slots not supported";
277 case DLADM_STATUS_INVALIDMACPREFIX
:
278 s
= "Invalid MAC address prefix value";
280 case DLADM_STATUS_INVALIDMACPREFIXLEN
:
281 s
= "Invalid MAC address prefix length";
283 case DLADM_STATUS_BADCPUID
:
284 s
= "non-existent processor ID";
286 case DLADM_STATUS_CPUERR
:
287 s
= "could not determine processor status";
289 case DLADM_STATUS_CPUNOTONLINE
:
290 s
= "processor not online";
292 case DLADM_STATUS_TOOMANYELEMENTS
:
293 s
= "too many elements specified";
295 case DLADM_STATUS_BADRANGE
:
298 case DLADM_STATUS_DB_NOTFOUND
:
299 s
= "database not found";
301 case DLADM_STATUS_DB_PARSE_ERR
:
302 s
= "database parse error";
304 case DLADM_STATUS_PROP_PARSE_ERR
:
305 s
= "property parse error";
307 case DLADM_STATUS_ATTR_PARSE_ERR
:
308 s
= "attribute parse error";
310 case DLADM_STATUS_FLOW_DB_ERR
:
311 s
= "flow database error";
313 case DLADM_STATUS_FLOW_DB_OPEN_ERR
:
314 s
= "flow database open error";
316 case DLADM_STATUS_FLOW_DB_PARSE_ERR
:
317 s
= "flow database parse error";
319 case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR
:
320 s
= "flow property database parse error";
322 case DLADM_STATUS_FLOW_ADD_ERR
:
323 s
= "flow add error";
325 case DLADM_STATUS_FLOW_WALK_ERR
:
326 s
= "flow walk error";
328 case DLADM_STATUS_FLOW_IDENTICAL
:
329 s
= "a flow with identical attributes exists";
331 case DLADM_STATUS_FLOW_INCOMPATIBLE
:
332 s
= "flow(s) with incompatible attributes exists";
334 case DLADM_STATUS_FLOW_EXISTS
:
335 s
= "link still has flows";
337 case DLADM_STATUS_PERSIST_FLOW_EXISTS
:
338 s
= "persistent flow with the same name exists";
340 case DLADM_STATUS_INVALID_IP
:
341 s
= "invalid IP address";
343 case DLADM_STATUS_INVALID_PREFIXLEN
:
344 s
= "invalid IP prefix length";
346 case DLADM_STATUS_INVALID_PROTOCOL
:
347 s
= "invalid IP protocol";
349 case DLADM_STATUS_INVALID_PORT
:
350 s
= "invalid port number";
352 case DLADM_STATUS_INVALID_DSF
:
353 s
= "invalid dsfield";
355 case DLADM_STATUS_INVALID_DSFMASK
:
356 s
= "invalid dsfield mask";
358 case DLADM_STATUS_INVALID_MACMARGIN
:
359 s
= "MTU check failed, use lower MTU or -f option";
361 case DLADM_STATUS_BADPROP
:
362 s
= "invalid property";
364 case DLADM_STATUS_MINMAXBW
:
365 s
= "minimum value for maxbw is 1200K";
367 case DLADM_STATUS_NO_HWRINGS
:
368 s
= "request hw rings failed";
370 case DLADM_STATUS_PERMONLY
:
371 s
= "change must be persistent";
373 case DLADM_STATUS_OPTMISSING
:
374 s
= "optional software not installed";
376 case DLADM_STATUS_IPTUNTYPE
:
377 s
= "invalid IP tunnel type";
379 case DLADM_STATUS_IPTUNTYPEREQD
:
380 s
= "IP tunnel type required";
382 case DLADM_STATUS_BADIPTUNLADDR
:
383 s
= "invalid local IP tunnel address";
385 case DLADM_STATUS_BADIPTUNRADDR
:
386 s
= "invalid remote IP tunnel address";
388 case DLADM_STATUS_ADDRINUSE
:
389 s
= "address already in use";
391 case DLADM_STATUS_POOLCPU
:
392 s
= "pool and cpus property are mutually exclusive";
394 case DLADM_STATUS_INVALID_PORT_INSTANCE
:
395 s
= "invalid IB phys link";
397 case DLADM_STATUS_PORT_IS_DOWN
:
400 case DLADM_STATUS_PARTITION_EXISTS
:
401 s
= "partition already exists";
403 case DLADM_STATUS_PKEY_NOT_PRESENT
:
404 s
= "PKEY is not present on the port";
406 case DLADM_STATUS_INVALID_PKEY
:
409 case DLADM_STATUS_NO_IB_HW_RESOURCE
:
410 s
= "IB internal resource not available";
412 case DLADM_STATUS_INVALID_PKEY_TBL_SIZE
:
413 s
= "invalid PKEY table size";
415 case DLADM_STATUS_PORT_NOPROTO
:
416 s
= "local or remote port requires transport";
418 case DLADM_STATUS_INVALID_MTU
:
419 s
= "MTU check failed, MTU outside of device's supported range";
422 s
= "<unknown error>";
425 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", dgettext(TEXT_DOMAIN
, s
));
430 * Convert a unix errno to a dladm_status_t.
431 * We only convert errnos that are likely to be encountered. All others
432 * are mapped to DLADM_STATUS_FAILED.
435 dladm_errno2status(int err
)
439 return (DLADM_STATUS_OK
);
441 return (DLADM_STATUS_BADARG
);
443 return (DLADM_STATUS_EXIST
);
445 return (DLADM_STATUS_NOTFOUND
);
447 return (DLADM_STATUS_TOOSMALL
);
449 return (DLADM_STATUS_NOMEM
);
451 return (DLADM_STATUS_NOTSUP
);
453 return (DLADM_STATUS_NONOTIF
);
456 return (DLADM_STATUS_DENIED
);
458 return (DLADM_STATUS_IOERR
);
460 return (DLADM_STATUS_LINKBUSY
);
462 return (DLADM_STATUS_TRYAGAIN
);
464 return (DLADM_STATUS_FLOW_EXISTS
);
466 return (DLADM_STATUS_FLOW_INCOMPATIBLE
);
468 return (DLADM_STATUS_FLOW_IDENTICAL
);
470 return (DLADM_STATUS_ADDRINUSE
);
472 return (DLADM_STATUS_FAILED
);
477 dladm_str2interval(char *oarg
, uint32_t *interval
)
483 val
= strtol(oarg
, &endp
, 10);
484 if (errno
!= 0 || val
<= 0 || *endp
!= '\0')
493 dladm_str2bw(char *oarg
, uint64_t *bw
)
499 n
= strtoull(oarg
, &endp
, 10);
501 if ((errno
!= 0) || (strlen(endp
) > 1))
502 return (DLADM_STATUS_BADARG
);
505 return (DLADM_STATUS_BADVAL
);
523 * percentages not supported for now,
526 return (DLADM_STATUS_NOTSUP
);
528 return (DLADM_STATUS_BADVAL
);
533 /* check for overflow */
535 return (DLADM_STATUS_BADARG
);
537 return (DLADM_STATUS_OK
);
541 * Convert bandwidth in bps to a string in Mbps. For values greater
542 * than 1Mbps or 1000000, print a whole Mbps value. For values that
543 * have fractional Mbps in whole Kbps, print the bandwidth in a manner
544 * similar to a floating point format.
556 dladm_bw2str(int64_t bw
, char *buf
)
560 kbps
= (bw
%1000000)/1000;
564 (void) snprintf(buf
, DLADM_STRSIZE
, "0.%03u", kbps
);
566 (void) snprintf(buf
, DLADM_STRSIZE
, "%5u.%03u", mbps
,
569 (void) snprintf(buf
, DLADM_STRSIZE
, "%5u", mbps
);
575 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
578 i_dladm_lock_db(const char *lock_file
, short type
)
583 if ((lock_fd
= open(lock_file
, O_RDWR
| O_CREAT
| O_TRUNC
,
588 lock
.l_whence
= SEEK_SET
;
592 if (fcntl(lock_fd
, F_SETLKW
, &lock
) < 0) {
595 (void) close(lock_fd
);
596 (void) unlink(lock_file
);
604 i_dladm_unlock_db(const char *lock_file
, int fd
)
611 lock
.l_type
= F_UNLCK
;
612 lock
.l_whence
= SEEK_SET
;
616 (void) fcntl(fd
, F_SETLKW
, &lock
);
618 (void) unlink(lock_file
);
622 * Given a link class, returns its class string.
625 dladm_class2str(datalink_class_t
class, char *buf
)
630 case DATALINK_CLASS_PHYS
:
633 case DATALINK_CLASS_VLAN
:
636 case DATALINK_CLASS_AGGR
:
639 case DATALINK_CLASS_VNIC
:
642 case DATALINK_CLASS_ETHERSTUB
:
645 case DATALINK_CLASS_IPTUN
:
648 case DATALINK_CLASS_SIMNET
:
651 case DATALINK_CLASS_BRIDGE
:
654 case DATALINK_CLASS_PART
:
662 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
667 * Given a physical link media type, returns its media type string.
670 dladm_media2str(uint32_t media
, char *buf
)
672 const char *s
= "--";
676 for (idx
= 0; idx
< MEDIATYPECOUNT
; idx
++) {
677 mt
= media_type_table
+ idx
;
678 if (mt
->media_type
== media
) {
679 s
= mt
->media_type_str
;
684 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
689 * Given a physical link media type string, returns its media type constant.
692 dladm_str2media(const char *buf
)
697 for (idx
= 0; idx
< MEDIATYPECOUNT
; idx
++) {
698 mt
= media_type_table
+ idx
;
699 if (strcasecmp(buf
, mt
->media_type_str
) == 0)
700 return (mt
->media_type
);
707 i_dladm_rw_db(dladm_handle_t handle
, const char *db_file
, mode_t db_perms
,
708 dladm_status_t (*process_db
)(dladm_handle_t
, void *, FILE *, FILE *),
709 void *arg
, boolean_t writeop
)
711 dladm_status_t status
= DLADM_STATUS_OK
;
712 FILE *fp
, *nfp
= NULL
;
713 char lock
[MAXPATHLEN
];
714 char file
[MAXPATHLEN
];
715 char newfile
[MAXPATHLEN
];
720 * If we are called from a boot script such as net-physical,
721 * it's quite likely that the root fs is still not writable.
722 * For this case, it's ok for the lock creation to fail since
723 * no one else could be accessing our configuration file.
725 db_basename
= strrchr(db_file
, '/');
726 if (db_basename
== NULL
|| db_basename
[1] == '\0')
727 return (dladm_errno2status(EINVAL
));
729 (void) snprintf(lock
, MAXPATHLEN
, "/tmp/%s.lock", db_basename
);
730 if ((lock_fd
= i_dladm_lock_db
731 (lock
, (writeop
? F_WRLCK
: F_RDLCK
))) < 0 && errno
!= EROFS
)
732 return (dladm_errno2status(errno
));
734 (void) snprintf(file
, MAXPATHLEN
, "%s/%s", dladm_rootdir
, db_file
);
735 if ((fp
= fopen(file
, (writeop
? "r+" : "r"))) == NULL
) {
738 i_dladm_unlock_db(lock
, lock_fd
);
740 return (DLADM_STATUS_DBNOTFOUND
);
742 return (dladm_errno2status(err
));
746 (void) snprintf(newfile
, MAXPATHLEN
, "%s/%s.new",
747 dladm_rootdir
, db_file
);
748 if ((nfd
= open(newfile
, O_WRONLY
| O_CREAT
| O_TRUNC
,
751 i_dladm_unlock_db(lock
, lock_fd
);
752 return (dladm_errno2status(errno
));
755 if ((nfp
= fdopen(nfd
, "w")) == NULL
) {
758 (void) unlink(newfile
);
759 i_dladm_unlock_db(lock
, lock_fd
);
760 return (dladm_errno2status(errno
));
763 status
= (*process_db
)(handle
, arg
, fp
, nfp
);
764 if (!writeop
|| status
!= DLADM_STATUS_OK
)
767 /* Set permissions on file to db_perms */
768 if (fchmod(nfd
, db_perms
) < 0) {
769 status
= dladm_errno2status(errno
);
774 * Configuration files need to be owned by the 'dladm' user and
777 if (fchown(nfd
, UID_DLADM
, GID_NETADM
) < 0) {
778 status
= dladm_errno2status(errno
);
782 if (fflush(nfp
) == EOF
) {
783 status
= dladm_errno2status(errno
);
789 if (rename(newfile
, file
) < 0) {
790 (void) unlink(newfile
);
791 i_dladm_unlock_db(lock
, lock_fd
);
792 return (dladm_errno2status(errno
));
795 i_dladm_unlock_db(lock
, lock_fd
);
796 return (DLADM_STATUS_OK
);
801 if (status
!= DLADM_STATUS_OK
)
802 (void) unlink(newfile
);
805 i_dladm_unlock_db(lock
, lock_fd
);
810 dladm_set_rootdir(const char *rootdir
)
814 if (rootdir
== NULL
|| *rootdir
!= '/' ||
815 (dp
= opendir(rootdir
)) == NULL
)
816 return (DLADM_STATUS_BADARG
);
818 (void) strncpy(dladm_rootdir
, rootdir
, MAXPATHLEN
);
820 return (DLADM_STATUS_OK
);
824 dladm_valid_linkname(const char *link
)
826 size_t len
= strlen(link
);
830 if (len
>= MAXLINKNAMELEN
)
833 /* Link name cannot start with a digit */
834 if (isdigit(link
[0]))
836 /* Link name must end with a number without leading zeroes */
838 while (isdigit(*cp
)) {
842 if (nd
== 0 || (nd
> 1 && *(cp
+ 1) == '0'))
846 * The legal characters in a link name are:
847 * alphanumeric (a-z, A-Z, 0-9), underscore ('_'), and '.'.
849 for (cp
= link
; *cp
!= '\0'; cp
++) {
850 if ((isalnum(*cp
) == 0) && (*cp
!= '_') && (*cp
!= '.'))
858 * Convert priority string to a value.
861 dladm_str2pri(char *token
, mac_priority_level_t
*pri
)
863 if (strlen(token
) == strlen("low") &&
864 strncasecmp(token
, "low", strlen("low")) == 0) {
866 } else if (strlen(token
) == strlen("medium") &&
867 strncasecmp(token
, "medium", strlen("medium")) == 0) {
869 } else if (strlen(token
) == strlen("high") &&
870 strncasecmp(token
, "high", strlen("high")) == 0) {
873 return (DLADM_STATUS_BADVAL
);
875 return (DLADM_STATUS_OK
);
879 * Convert priority value to a string.
882 dladm_pri2str(mac_priority_level_t pri
, char *buf
)
900 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", dgettext(TEXT_DOMAIN
, s
));
905 * Convert protect string to a value.
908 dladm_str2protect(char *token
, uint32_t *ptype
)
913 for (i
= 0; i
< LPTYPES
; i
++) {
914 lp
= &link_protect_types
[i
];
915 if (strcmp(token
, lp
->lp_name
) == 0) {
916 *ptype
= lp
->lp_type
;
917 return (DLADM_STATUS_OK
);
920 return (DLADM_STATUS_BADVAL
);
924 * Convert protect value to a string.
927 dladm_protect2str(uint32_t ptype
, char *buf
)
929 const char *s
= "--";
933 for (i
= 0; i
< LPTYPES
; i
++) {
934 lp
= &link_protect_types
[i
];
935 if (lp
->lp_type
== ptype
) {
940 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", dgettext(TEXT_DOMAIN
, s
));
945 * Convert an IPv4 address to/from a string.
948 dladm_ipv4addr2str(void *addr
, char *buf
)
950 if (inet_ntop(AF_INET
, addr
, buf
, INET_ADDRSTRLEN
) == NULL
)
957 dladm_str2ipv4addr(char *token
, void *addr
)
959 return (inet_pton(AF_INET
, token
, addr
) == 1 ?
960 DLADM_STATUS_OK
: DLADM_STATUS_INVALID_IP
);
964 dladm_ipv6addr2str(void *addr
, char *buf
)
966 if (inet_ntop(AF_INET6
, addr
, buf
, INET6_ADDRSTRLEN
) == NULL
)
973 dladm_str2ipv6addr(char *token
, void *addr
)
975 return (inet_pton(AF_INET6
, token
, addr
) == 1 ?
976 DLADM_STATUS_OK
: DLADM_STATUS_INVALID_IP
);
980 * Find the set bits in a mask.
981 * This is used for expanding a bitmask into individual sub-masks
982 * which can be used for further processing.
985 dladm_find_setbits32(uint32_t mask
, uint32_t *list
, uint32_t *cnt
)
989 for (i
= 0; i
< 32; i
++) {
990 if (((1 << i
) & mask
) != 0)
997 dladm_free_args(dladm_arg_list_t
*list
)
1006 dladm_parse_args(char *str
, dladm_arg_list_t
**listp
, boolean_t novalues
)
1008 dladm_arg_list_t
*list
;
1009 dladm_arg_info_t
*aip
;
1014 return (DLADM_STATUS_BADVAL
);
1017 return (DLADM_STATUS_OK
);
1019 list
= malloc(sizeof (dladm_arg_list_t
));
1021 return (dladm_errno2status(errno
));
1024 list
->al_buf
= buf
= strdup(str
);
1026 return (dladm_errno2status(errno
));
1031 for (i
= 0; i
< len
; i
++) {
1033 boolean_t match
= (c
== '=' || c
== ',');
1035 if (!match
&& i
!= len
- 1)
1044 if (aip
!= NULL
&& c
!= '=') {
1045 if (aip
->ai_count
> DLADM_MAX_ARG_VALS
)
1051 aip
->ai_val
[aip
->ai_count
] = curr
;
1054 if (list
->al_count
> DLADM_MAX_ARG_VALS
)
1057 aip
= &list
->al_info
[list
->al_count
];
1058 aip
->ai_name
= curr
;
1068 return (DLADM_STATUS_OK
);
1071 dladm_free_args(list
);
1072 return (DLADM_STATUS_FAILED
);
1076 * mac_propval_range_t functions. Currently implemented for only
1077 * ranges of uint32_t elements, but can be expanded as required.
1080 * Convert an array of strings (which can be ranges or individual
1081 * elements) into a single mac_propval_range_t structure which
1082 * is allocated here but should be freed by the caller.
1085 dladm_strs2range(char **prop_val
, uint_t val_cnt
, mac_propval_type_t type
,
1086 mac_propval_range_t
**range
)
1090 mac_propval_range_t
*rangep
;
1091 dladm_status_t status
= DLADM_STATUS_OK
;
1094 case MAC_PROPVAL_UINT32
: {
1095 mac_propval_uint32_range_t
*ur
;
1097 /* Allocate range structure */
1098 rangep
= malloc(sizeof (mac_propval_range_t
) +
1099 (val_cnt
-1)*(sizeof (mac_propval_uint32_range_t
)));
1101 return (DLADM_STATUS_NOMEM
);
1103 rangep
->mpr_count
= 0;
1104 ur
= &rangep
->mpr_range_uint32
[0];
1105 for (i
= 0; i
< val_cnt
; i
++, ur
++) {
1107 if (strchr(prop_val
[i
], '-') == NULL
) {
1108 /* single element */
1109 ur
->mpur_min
= ur
->mpur_max
=
1110 strtol(prop_val
[i
], &endp
, 10);
1111 if ((endp
!= NULL
) && (*endp
!= '\0')) {
1112 return (DLADM_STATUS_BADRANGE
);
1115 /* range of elements */
1116 ur
->mpur_min
= strtol(prop_val
[i
], &endp
, 10);
1118 return (DLADM_STATUS_BADRANGE
);
1119 ur
->mpur_max
= strtol(endp
, &endp
, 10);
1120 if (endp
!= NULL
&& *endp
!= '\0' ||
1121 ur
->mpur_max
< ur
->mpur_min
)
1122 return (DLADM_STATUS_BADRANGE
);
1124 rangep
->mpr_count
++;
1129 return (DLADM_STATUS_BADVAL
);
1132 rangep
->mpr_type
= type
;
1139 * Convert a mac_propval_range_t structure into an array of elements.
1142 dladm_range2list(mac_propval_range_t
*rangep
, void *elem
, uint_t
*nelem
)
1145 dladm_status_t status
= DLADM_STATUS_OK
;
1147 switch (rangep
->mpr_type
) {
1148 case MAC_PROPVAL_UINT32
: {
1149 mac_propval_uint32_range_t
*ur
;
1150 uint32_t *elem32
= elem
;
1153 ur
= &rangep
->mpr_range_uint32
[0];
1154 for (i
= 0; i
< rangep
->mpr_count
; i
++, ur
++) {
1155 for (j
= 0; j
<= ur
->mpur_max
- ur
->mpur_min
; j
++) {
1156 elem32
[k
++] = ur
->mpur_min
+ j
;
1158 status
= DLADM_STATUS_TOOMANYELEMENTS
;
1167 status
= DLADM_STATUS_BADVAL
;
1174 * Convert a mac_propval_range_t structure into an array of strings
1175 * of single elements or ranges.
1178 dladm_range2strs(mac_propval_range_t
*rangep
, char **prop_val
)
1182 switch (rangep
->mpr_type
) {
1183 case MAC_PROPVAL_UINT32
: {
1184 mac_propval_uint32_range_t
*ur
;
1186 /* Write ranges and individual elements */
1187 ur
= &rangep
->mpr_range_uint32
[0];
1188 for (i
= 0; i
< rangep
->mpr_count
; i
++, ur
++) {
1189 if (ur
->mpur_min
== ur
->mpur_max
) {
1190 /* single element */
1191 (void) snprintf(prop_val
[i
], DLADM_PROP_VAL_MAX
,
1192 "%u", ur
->mpur_min
);
1194 /* range of elements */
1195 (void) snprintf(prop_val
[i
], DLADM_PROP_VAL_MAX
,
1196 "%u-%u", ur
->mpur_min
, ur
->mpur_max
);
1208 uint32cmp(const void *a
, const void *b
)
1210 return (*(uint32_t *)a
- *(uint32_t *)b
);
1214 * Sort and convert an array of elements into a single
1215 * mac_propval_range_t structure which is allocated here but
1216 * should be freed by the caller.
1219 dladm_list2range(void *elem
, uint_t nelem
, mac_propval_type_t type
,
1220 mac_propval_range_t
**range
)
1224 mac_propval_range_t
*rangep
;
1225 dladm_status_t status
= DLADM_STATUS_OK
;
1228 case MAC_PROPVAL_UINT32
: {
1229 mac_propval_uint32_range_t
*ur
;
1230 uint32_t *elem32
= elem
;
1233 /* Allocate range structure */
1234 rangep
= malloc(sizeof (mac_propval_range_t
) +
1235 (nelem
-1)*(sizeof (mac_propval_uint32_range_t
)));
1237 return (DLADM_STATUS_NOMEM
);
1239 /* Allocate array for sorting */
1240 sort32
= malloc(nelem
* sizeof (uint32_t));
1241 if (sort32
== NULL
) {
1243 return (DLADM_STATUS_NOMEM
);
1246 /* Copy and sort list */
1247 for (i
= 0; i
< nelem
; i
++)
1248 sort32
[i
] = elem32
[i
];
1250 qsort(sort32
, nelem
, sizeof (uint32_t), uint32cmp
);
1252 /* Convert list to ranges */
1253 ur
= &rangep
->mpr_range_uint32
[0];
1254 ur
->mpur_min
= ur
->mpur_max
= sort32
[0];
1255 for (i
= 1; i
< nelem
; i
++) {
1256 if (sort32
[i
]-sort32
[i
-1] == 1) {
1257 /* part of current range */
1258 ur
->mpur_max
= sort32
[i
];
1260 /* start a new range */
1262 ur
->mpur_min
= ur
->mpur_max
= sort32
[i
];
1269 return (DLADM_STATUS_BADRANGE
);
1272 rangep
->mpr_type
= type
;
1273 rangep
->mpr_count
= nr
+ 1;