18275SEric Cheng /* 28275SEric Cheng * CDDL HEADER START 38275SEric Cheng * 48275SEric Cheng * The contents of this file are subject to the terms of the 58275SEric Cheng * Common Development and Distribution License (the "License"). 68275SEric Cheng * You may not use this file except in compliance with the License. 78275SEric Cheng * 88275SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98275SEric Cheng * or http://www.opensolaris.org/os/licensing. 108275SEric Cheng * See the License for the specific language governing permissions 118275SEric Cheng * and limitations under the License. 128275SEric Cheng * 138275SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 148275SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158275SEric Cheng * If applicable, add the following below this CDDL HEADER, with the 168275SEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 178275SEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 188275SEric Cheng * 198275SEric Cheng * CDDL HEADER END 208275SEric Cheng */ 218275SEric Cheng /* 22*12309SMichael.Lim@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 238275SEric Cheng */ 248275SEric Cheng 258275SEric Cheng #include <errno.h> 268275SEric Cheng #include <stdlib.h> 278275SEric Cheng #include <strings.h> 288275SEric Cheng #include <sys/mac_flow.h> 298275SEric Cheng #include <sys/types.h> 308275SEric Cheng #include <sys/socket.h> 318275SEric Cheng #include <netinet/in.h> 328275SEric Cheng #include <arpa/inet.h> 338275SEric Cheng #include <netdb.h> 348275SEric Cheng #include <net/if_types.h> 358275SEric Cheng #include <net/if_dl.h> 368275SEric Cheng #include <inet/ip.h> 378275SEric Cheng #include <inet/ip6.h> 388275SEric Cheng 398275SEric Cheng #include <libdladm.h> 408275SEric Cheng #include <libdlflow.h> 418275SEric Cheng #include <libdlflow_impl.h> 428275SEric Cheng 438275SEric Cheng /* max port number for UDP, TCP & SCTP */ 448275SEric Cheng #define MAX_PORT 65535 458275SEric Cheng 468275SEric Cheng static fad_checkf_t do_check_local_ip; 478275SEric Cheng static fad_checkf_t do_check_remote_ip; 488275SEric Cheng static fad_checkf_t do_check_protocol; 498275SEric Cheng static fad_checkf_t do_check_local_port; 5010734SEric Cheng static fad_checkf_t do_check_remote_port; 518275SEric Cheng 528275SEric Cheng static dladm_status_t do_check_port(char *, boolean_t, flow_desc_t *); 538275SEric Cheng 548275SEric Cheng static fattr_desc_t attr_table[] = { 5510734SEric Cheng { "local_ip", do_check_local_ip }, 5610734SEric Cheng { "remote_ip", do_check_remote_ip }, 5710734SEric Cheng { "transport", do_check_protocol }, 5810734SEric Cheng { "local_port", do_check_local_port }, 5910734SEric Cheng { "remote_port", do_check_remote_port }, 6010734SEric Cheng { "dsfield", do_check_dsfield }, 618275SEric Cheng }; 628275SEric Cheng 638275SEric Cheng #define DLADM_MAX_FLOWATTRS (sizeof (attr_table) / sizeof (fattr_desc_t)) 648275SEric Cheng 658275SEric Cheng static dladm_status_t 668275SEric Cheng do_check_local_ip(char *attr_val, flow_desc_t *fdesc) 678275SEric Cheng { 688275SEric Cheng return (do_check_ip_addr(attr_val, B_TRUE, fdesc)); 698275SEric Cheng } 708275SEric Cheng 718275SEric Cheng static dladm_status_t 728275SEric Cheng do_check_remote_ip(char *attr_val, flow_desc_t *fdesc) 738275SEric Cheng { 748275SEric Cheng return (do_check_ip_addr(attr_val, B_FALSE, fdesc)); 758275SEric Cheng } 768275SEric Cheng 778275SEric Cheng dladm_status_t 788275SEric Cheng do_check_ip_addr(char *addr_str, boolean_t local, flow_desc_t *fd) 798275SEric Cheng { 808275SEric Cheng dladm_status_t status; 818558SGirish.Moodalbail@Sun.COM int prefix_max, prefix_len = 0; 828275SEric Cheng char *prefix_str, *endp = NULL; 838275SEric Cheng flow_mask_t mask; 848275SEric Cheng in6_addr_t *addr; 858275SEric Cheng uchar_t *netmask; 868558SGirish.Moodalbail@Sun.COM struct in_addr v4addr; 878558SGirish.Moodalbail@Sun.COM struct in6_addr v6addr; 888558SGirish.Moodalbail@Sun.COM int family; 898275SEric Cheng 908275SEric Cheng if ((prefix_str = strchr(addr_str, '/')) != NULL) { 918275SEric Cheng *prefix_str++ = '\0'; 928275SEric Cheng errno = 0; 938275SEric Cheng prefix_len = (int)strtol(prefix_str, &endp, 10); 948275SEric Cheng if (errno != 0 || prefix_len == 0 || *endp != '\0') 958275SEric Cheng return (DLADM_STATUS_INVALID_PREFIXLEN); 968275SEric Cheng } 978558SGirish.Moodalbail@Sun.COM if (inet_pton(AF_INET, addr_str, &v4addr.s_addr) == 1) { 988558SGirish.Moodalbail@Sun.COM family = AF_INET; 998558SGirish.Moodalbail@Sun.COM } else if (inet_pton(AF_INET6, addr_str, v6addr.s6_addr) == 1) { 1008558SGirish.Moodalbail@Sun.COM family = AF_INET6; 1018558SGirish.Moodalbail@Sun.COM } else { 1028275SEric Cheng return (DLADM_STATUS_INVALID_IP); 1038558SGirish.Moodalbail@Sun.COM } 1048275SEric Cheng 1058275SEric Cheng mask = FLOW_IP_VERSION; 1068275SEric Cheng if (local) { 1078275SEric Cheng mask |= FLOW_IP_LOCAL; 1088275SEric Cheng addr = &fd->fd_local_addr; 1098275SEric Cheng netmask = (uchar_t *)&fd->fd_local_netmask; 1108275SEric Cheng } else { 1118275SEric Cheng mask |= FLOW_IP_REMOTE; 1128275SEric Cheng addr = &fd->fd_remote_addr; 1138275SEric Cheng netmask = (uchar_t *)&fd->fd_remote_netmask; 1148275SEric Cheng } 1158275SEric Cheng 1168558SGirish.Moodalbail@Sun.COM if (family == AF_INET) { 1178558SGirish.Moodalbail@Sun.COM IN6_INADDR_TO_V4MAPPED(&v4addr, addr); 1188275SEric Cheng prefix_max = IP_ABITS; 1198275SEric Cheng fd->fd_ipversion = IPV4_VERSION; 1208275SEric Cheng netmask = (uchar_t *) 1218275SEric Cheng &(V4_PART_OF_V6((*((in6_addr_t *)(void *)netmask)))); 1228558SGirish.Moodalbail@Sun.COM } else { 1238558SGirish.Moodalbail@Sun.COM *addr = v6addr; 1248275SEric Cheng prefix_max = IPV6_ABITS; 1258275SEric Cheng fd->fd_ipversion = IPV6_VERSION; 1268275SEric Cheng } 1278275SEric Cheng 1288275SEric Cheng if (prefix_len == 0) 1298275SEric Cheng prefix_len = prefix_max; 1308275SEric Cheng 1318275SEric Cheng status = dladm_prefixlen2mask(prefix_len, prefix_max, netmask); 1328275SEric Cheng 1338275SEric Cheng if (status != DLADM_STATUS_OK) { 1348275SEric Cheng return (DLADM_STATUS_INVALID_PREFIXLEN); 1358275SEric Cheng } 1368275SEric Cheng 1378275SEric Cheng fd->fd_mask |= mask; 1388275SEric Cheng return (DLADM_STATUS_OK); 1398275SEric Cheng } 1408275SEric Cheng 1418275SEric Cheng dladm_status_t 1428275SEric Cheng do_check_protocol(char *attr_val, flow_desc_t *fdesc) 1438275SEric Cheng { 1448275SEric Cheng uint8_t protocol; 1458275SEric Cheng 1468275SEric Cheng protocol = dladm_str2proto(attr_val); 1478275SEric Cheng 1488275SEric Cheng if (protocol != 0) { 1498275SEric Cheng fdesc->fd_mask |= FLOW_IP_PROTOCOL; 1508275SEric Cheng fdesc->fd_protocol = protocol; 1518275SEric Cheng return (DLADM_STATUS_OK); 1528275SEric Cheng } else { 1538275SEric Cheng return (DLADM_STATUS_INVALID_PROTOCOL); 1548275SEric Cheng } 1558275SEric Cheng } 1568275SEric Cheng 1578275SEric Cheng dladm_status_t 1588275SEric Cheng do_check_local_port(char *attr_val, flow_desc_t *fdesc) 1598275SEric Cheng { 1608275SEric Cheng return (do_check_port(attr_val, B_TRUE, fdesc)); 1618275SEric Cheng } 1628275SEric Cheng 1638275SEric Cheng dladm_status_t 16410734SEric Cheng do_check_remote_port(char *attr_val, flow_desc_t *fdesc) 16510734SEric Cheng { 16610734SEric Cheng return (do_check_port(attr_val, B_FALSE, fdesc)); 16710734SEric Cheng } 16810734SEric Cheng 16910734SEric Cheng dladm_status_t 1708275SEric Cheng do_check_port(char *attr_val, boolean_t local, flow_desc_t *fdesc) 1718275SEric Cheng { 1728275SEric Cheng char *endp = NULL; 1738275SEric Cheng long val; 1748275SEric Cheng 17510734SEric Cheng val = strtol(attr_val, &endp, 10); 17610734SEric Cheng if (val < 1 || val > MAX_PORT || *endp != '\0') 17710734SEric Cheng return (DLADM_STATUS_INVALID_PORT); 1788275SEric Cheng if (local) { 1798275SEric Cheng fdesc->fd_mask |= FLOW_ULP_PORT_LOCAL; 1808275SEric Cheng fdesc->fd_local_port = htons((uint16_t)val); 1818275SEric Cheng } else { 18210734SEric Cheng fdesc->fd_mask |= FLOW_ULP_PORT_REMOTE; 18310734SEric Cheng fdesc->fd_remote_port = htons((uint16_t)val); 1848275SEric Cheng } 1858275SEric Cheng 1868275SEric Cheng return (DLADM_STATUS_OK); 1878275SEric Cheng } 1888275SEric Cheng 1898275SEric Cheng /* 1908275SEric Cheng * Check for invalid and/or duplicate attribute specification 1918275SEric Cheng */ 1928275SEric Cheng static dladm_status_t 1938275SEric Cheng flow_attrlist_check(dladm_arg_list_t *attrlist) 1948275SEric Cheng { 1958275SEric Cheng int i, j; 1968275SEric Cheng boolean_t isset[DLADM_MAX_FLOWATTRS]; 1978275SEric Cheng boolean_t matched; 1988275SEric Cheng 1998275SEric Cheng for (j = 0; j < DLADM_MAX_FLOWATTRS; j++) 2008275SEric Cheng isset[j] = B_FALSE; 2018275SEric Cheng 2028275SEric Cheng for (i = 0; i < attrlist->al_count; i++) { 2038275SEric Cheng matched = B_FALSE; 2048275SEric Cheng for (j = 0; j < DLADM_MAX_FLOWATTRS; j++) { 2058275SEric Cheng if (strcmp(attrlist->al_info[i].ai_name, 2068275SEric Cheng attr_table[j].ad_name) == 0) { 2078275SEric Cheng if (isset[j]) 2088275SEric Cheng return (DLADM_STATUS_FLOW_INCOMPATIBLE); 2098275SEric Cheng else 2108275SEric Cheng isset[j] = B_TRUE; 2118275SEric Cheng matched = B_TRUE; 2128275SEric Cheng } 2138275SEric Cheng } 2148275SEric Cheng /* 2158275SEric Cheng * if the attribute did not match any of the attribute in 2168275SEric Cheng * attr_table, then it's an invalid attribute. 2178275SEric Cheng */ 2188275SEric Cheng if (!matched) 2198275SEric Cheng return (DLADM_STATUS_BADARG); 2208275SEric Cheng } 2218275SEric Cheng return (DLADM_STATUS_OK); 2228275SEric Cheng } 2238275SEric Cheng 2248275SEric Cheng /* 2258275SEric Cheng * Convert an attribute list to a flow_desc_t using the attribute ad_check() 2268275SEric Cheng * functions. 2278275SEric Cheng */ 2288275SEric Cheng dladm_status_t 2298275SEric Cheng dladm_flow_attrlist_extract(dladm_arg_list_t *attrlist, flow_desc_t *flowdesc) 2308275SEric Cheng { 2318275SEric Cheng dladm_status_t status = DLADM_STATUS_BADARG; 2328275SEric Cheng int i; 2338275SEric Cheng 2348275SEric Cheng for (i = 0; i < attrlist->al_count; i++) { 2358275SEric Cheng dladm_arg_info_t *aip = &attrlist->al_info[i]; 2368275SEric Cheng int j; 2378275SEric Cheng 2388275SEric Cheng for (j = 0; j < DLADM_MAX_FLOWATTRS; j++) { 2398275SEric Cheng fattr_desc_t *adp = &attr_table[j]; 2408275SEric Cheng 2418275SEric Cheng if (strcasecmp(aip->ai_name, adp->ad_name) != 0) 2428275SEric Cheng continue; 2438275SEric Cheng 2448275SEric Cheng if ((aip->ai_val == NULL) || (*aip->ai_val == NULL)) 2458275SEric Cheng return (DLADM_STATUS_BADARG); 2468275SEric Cheng 2478275SEric Cheng if (adp->ad_check != NULL) 2488275SEric Cheng status = adp->ad_check(*aip->ai_val, flowdesc); 2498275SEric Cheng else 2508275SEric Cheng status = DLADM_STATUS_BADARG; 2518275SEric Cheng 2528275SEric Cheng if (status != DLADM_STATUS_OK) 2538275SEric Cheng return (status); 2548275SEric Cheng } 2558275SEric Cheng } 256*12309SMichael.Lim@Sun.COM 257*12309SMichael.Lim@Sun.COM /* 258*12309SMichael.Lim@Sun.COM * Make sure protocol is specified if either local or 259*12309SMichael.Lim@Sun.COM * remote port is specified. 260*12309SMichael.Lim@Sun.COM */ 261*12309SMichael.Lim@Sun.COM if ((flowdesc->fd_mask & 262*12309SMichael.Lim@Sun.COM (FLOW_ULP_PORT_LOCAL | FLOW_ULP_PORT_REMOTE)) != 0 && 263*12309SMichael.Lim@Sun.COM (flowdesc->fd_mask & FLOW_IP_PROTOCOL) == 0) 264*12309SMichael.Lim@Sun.COM return (DLADM_STATUS_PORT_NOPROTO); 265*12309SMichael.Lim@Sun.COM 2668275SEric Cheng return (status); 2678275SEric Cheng } 2688275SEric Cheng 2698275SEric Cheng void 2708275SEric Cheng dladm_free_attrs(dladm_arg_list_t *list) 2718275SEric Cheng { 2728275SEric Cheng dladm_free_args(list); 2738275SEric Cheng } 2748275SEric Cheng 2758275SEric Cheng dladm_status_t 2768275SEric Cheng dladm_parse_flow_attrs(char *str, dladm_arg_list_t **listp, boolean_t novalues) 2778275SEric Cheng { 2788275SEric Cheng 2798275SEric Cheng if (dladm_parse_args(str, listp, novalues) 2808275SEric Cheng != DLADM_STATUS_OK) 2818275SEric Cheng return (DLADM_STATUS_ATTR_PARSE_ERR); 2828275SEric Cheng 2839055SMichael.Lim@Sun.COM if (*listp != NULL && flow_attrlist_check(*listp) 2849055SMichael.Lim@Sun.COM != DLADM_STATUS_OK) { 2858275SEric Cheng dladm_free_attrs(*listp); 2868275SEric Cheng return (DLADM_STATUS_ATTR_PARSE_ERR); 2878275SEric Cheng } 2888275SEric Cheng 2898275SEric Cheng return (DLADM_STATUS_OK); 2908275SEric Cheng } 2918275SEric Cheng 2928275SEric Cheng dladm_status_t 2938275SEric Cheng do_check_dsfield(char *str, flow_desc_t *fd) 2948275SEric Cheng { 2958275SEric Cheng char *mask_str, *endp = NULL; 2968275SEric Cheng uint_t mask = 0xff, value; 2978275SEric Cheng 2988275SEric Cheng if ((mask_str = strchr(str, ':')) != NULL) { 2998275SEric Cheng *mask_str++ = '\0'; 3008275SEric Cheng errno = 0; 3018275SEric Cheng mask = strtoul(mask_str, &endp, 16); 3028275SEric Cheng if (errno != 0 || mask == 0 || mask > 0xff || 3038275SEric Cheng *endp != '\0') 3048275SEric Cheng return (DLADM_STATUS_INVALID_DSFMASK); 3058275SEric Cheng } 3068275SEric Cheng errno = 0; 3078275SEric Cheng endp = NULL; 3088275SEric Cheng value = strtoul(str, &endp, 16); 3098275SEric Cheng if (errno != 0 || value == 0 || value > 0xff || *endp != '\0') 3108275SEric Cheng return (DLADM_STATUS_INVALID_DSF); 3118275SEric Cheng 3128275SEric Cheng fd->fd_dsfield = (uint8_t)value; 3138275SEric Cheng fd->fd_dsfield_mask = (uint8_t)mask; 3148275SEric Cheng fd->fd_mask |= FLOW_IP_DSFIELD; 3158275SEric Cheng return (DLADM_STATUS_OK); 3168275SEric Cheng } 3178275SEric Cheng 3188275SEric Cheng char * 3198275SEric Cheng dladm_proto2str(uint8_t protocol) 3208275SEric Cheng { 3218275SEric Cheng if (protocol == IPPROTO_TCP) 3228275SEric Cheng return ("tcp"); 3238275SEric Cheng if (protocol == IPPROTO_UDP) 3248275SEric Cheng return ("udp"); 3258275SEric Cheng if (protocol == IPPROTO_SCTP) 3268275SEric Cheng return ("sctp"); 3278275SEric Cheng if (protocol == IPPROTO_ICMPV6) 3288275SEric Cheng return ("icmpv6"); 3298275SEric Cheng if (protocol == IPPROTO_ICMP) 3308275SEric Cheng return ("icmp"); 3318275SEric Cheng else 3328275SEric Cheng return (""); 3338275SEric Cheng } 3348275SEric Cheng 3358275SEric Cheng uint8_t 3368275SEric Cheng dladm_str2proto(const char *protostr) 3378275SEric Cheng { 3388275SEric Cheng if (strncasecmp(protostr, "tcp", 3) == 0) 3398275SEric Cheng return (IPPROTO_TCP); 3408275SEric Cheng else if (strncasecmp(protostr, "udp", 3) == 0) 3418275SEric Cheng return (IPPROTO_UDP); 3428275SEric Cheng else if (strncasecmp(protostr, "sctp", 4) == 0) 3438275SEric Cheng return (IPPROTO_SCTP); 3448275SEric Cheng else if (strncasecmp(protostr, "icmpv6", 6) == 0) 3458275SEric Cheng return (IPPROTO_ICMPV6); 3468275SEric Cheng else if (strncasecmp(protostr, "icmp", 4) == 0) 3478275SEric Cheng return (IPPROTO_ICMP); 3488275SEric Cheng 3498275SEric Cheng return (0); 3508275SEric Cheng } 3518275SEric Cheng 3528275SEric Cheng void 3538275SEric Cheng dladm_flow_attr_ip2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len) 3548275SEric Cheng { 3558275SEric Cheng flow_desc_t fdesc = attrp->fa_flow_desc; 3568275SEric Cheng struct in_addr ipaddr; 3578275SEric Cheng int prefix_len, prefix_max; 3588275SEric Cheng char *cp, abuf[INET6_ADDRSTRLEN]; 3598275SEric Cheng 3608275SEric Cheng if (fdesc.fd_mask & FLOW_IP_LOCAL) { 3618275SEric Cheng if (fdesc.fd_ipversion == IPV6_VERSION) { 3628275SEric Cheng (void) inet_ntop(AF_INET6, &fdesc.fd_local_addr, abuf, 3638275SEric Cheng INET6_ADDRSTRLEN); 3648275SEric Cheng cp = abuf; 3658275SEric Cheng prefix_max = IPV6_ABITS; 3668275SEric Cheng } else { 3678275SEric Cheng ipaddr.s_addr = fdesc.fd_local_addr._S6_un._S6_u32[3]; 3688275SEric Cheng cp = inet_ntoa(ipaddr); 3698275SEric Cheng prefix_max = IP_ABITS; 3708275SEric Cheng } 3718275SEric Cheng (void) dladm_mask2prefixlen(&fdesc.fd_local_netmask, 3728275SEric Cheng prefix_max, &prefix_len); 3738275SEric Cheng (void) snprintf(buf, buf_len, "LCL:%s/%d ", cp, prefix_len); 3748275SEric Cheng } else if (fdesc.fd_mask & FLOW_IP_REMOTE) { 3758275SEric Cheng if (fdesc.fd_ipversion == IPV6_VERSION) { 3768275SEric Cheng (void) inet_ntop(AF_INET6, &fdesc.fd_remote_addr, abuf, 3778275SEric Cheng INET6_ADDRSTRLEN); 3788275SEric Cheng cp = abuf; 3798275SEric Cheng prefix_max = IPV6_ABITS; 3808275SEric Cheng } else { 3818275SEric Cheng ipaddr.s_addr = fdesc.fd_remote_addr._S6_un._S6_u32[3]; 3828275SEric Cheng cp = inet_ntoa(ipaddr); 3838275SEric Cheng prefix_max = IP_ABITS; 3848275SEric Cheng } 3858275SEric Cheng (void) dladm_mask2prefixlen(&fdesc.fd_remote_netmask, 3868275SEric Cheng prefix_max, &prefix_len); 3878275SEric Cheng (void) snprintf(buf, buf_len, "RMT:%s/%d ", cp, prefix_len); 3888275SEric Cheng } else { 3898275SEric Cheng buf[0] = '\0'; 3908275SEric Cheng } 3918275SEric Cheng } 3928275SEric Cheng 3938275SEric Cheng void 3948275SEric Cheng dladm_flow_attr_proto2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len) 3958275SEric Cheng { 3968275SEric Cheng flow_desc_t fdesc = attrp->fa_flow_desc; 3978275SEric Cheng 3988275SEric Cheng (void) snprintf(buf, buf_len, "%s", 3998275SEric Cheng dladm_proto2str(fdesc.fd_protocol)); 4008275SEric Cheng } 4018275SEric Cheng 4028275SEric Cheng void 4038275SEric Cheng dladm_flow_attr_port2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len) 4048275SEric Cheng { 4058275SEric Cheng flow_desc_t fdesc = attrp->fa_flow_desc; 4068275SEric Cheng 4078275SEric Cheng if (fdesc.fd_mask & FLOW_ULP_PORT_LOCAL) { 4088275SEric Cheng (void) snprintf(buf, buf_len, "%d", 4098275SEric Cheng ntohs(fdesc.fd_local_port)); 41010734SEric Cheng } else if (fdesc.fd_mask & FLOW_ULP_PORT_REMOTE) { 41110734SEric Cheng (void) snprintf(buf, buf_len, "%d", 41210734SEric Cheng ntohs(fdesc.fd_remote_port)); 4138275SEric Cheng } else { 4148275SEric Cheng buf[0] = '\0'; 4158275SEric Cheng } 4168275SEric Cheng } 4178275SEric Cheng 4188275SEric Cheng void 4198275SEric Cheng dladm_flow_attr_dsfield2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len) 4208275SEric Cheng { 4218275SEric Cheng flow_desc_t fdesc = attrp->fa_flow_desc; 4228275SEric Cheng 4238275SEric Cheng if (fdesc.fd_mask & FLOW_IP_DSFIELD) { 4248275SEric Cheng (void) snprintf(buf, buf_len, "0x%x:0x%x", 4258275SEric Cheng fdesc.fd_dsfield, fdesc.fd_dsfield_mask); 4268275SEric Cheng } else { 4278275SEric Cheng buf[0] = '\0'; 4288275SEric Cheng } 4298275SEric Cheng } 430