xref: /titanic_44/usr/src/uts/common/os/iscsiboot_prop.c (revision db8b037b5616a366b7dfdc01ef9552f02f9adfdd)
16cefaae1SJack Meng /*
26cefaae1SJack Meng  * CDDL HEADER START
36cefaae1SJack Meng  *
46cefaae1SJack Meng  * The contents of this file are subject to the terms of the
56cefaae1SJack Meng  * Common Development and Distribution License (the "License").
66cefaae1SJack Meng  * You may not use this file except in compliance with the License.
76cefaae1SJack Meng  *
86cefaae1SJack Meng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96cefaae1SJack Meng  * or http://www.opensolaris.org/os/licensing.
106cefaae1SJack Meng  * See the License for the specific language governing permissions
116cefaae1SJack Meng  * and limitations under the License.
126cefaae1SJack Meng  *
136cefaae1SJack Meng  * When distributing Covered Code, include this CDDL HEADER in each
146cefaae1SJack Meng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156cefaae1SJack Meng  * If applicable, add the following below this CDDL HEADER, with the
166cefaae1SJack Meng  * fields enclosed by brackets "[]" replaced with your own identifying
176cefaae1SJack Meng  * information: Portions Copyright [yyyy] [name of copyright owner]
186cefaae1SJack Meng  *
196cefaae1SJack Meng  * CDDL HEADER END
206cefaae1SJack Meng  */
216cefaae1SJack Meng 
226cefaae1SJack Meng /*
23dedec472SJack Meng  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
246cefaae1SJack Meng  * Use is subject to license terms.
256cefaae1SJack Meng  */
266cefaae1SJack Meng 
276cefaae1SJack Meng /*
286cefaae1SJack Meng  * Commmon routines, handling iscsi boot props
296cefaae1SJack Meng  */
306cefaae1SJack Meng 
316cefaae1SJack Meng #include <sys/types.h>
32*db8b037bSRichard PALO #include <sys/null.h>
336cefaae1SJack Meng #include <sys/bootprops.h>
346cefaae1SJack Meng #include <sys/cmn_err.h>
356cefaae1SJack Meng #include <sys/socket.h>
366cefaae1SJack Meng #include <sys/kmem.h>
376cefaae1SJack Meng #include <netinet/in.h>
386cefaae1SJack Meng 
396cefaae1SJack Meng extern void *memset(void *s, int c, size_t n);
406cefaae1SJack Meng extern int memcmp(const void *s1, const void *s2, size_t n);
416cefaae1SJack Meng extern void bcopy(const void *s1, void *s2, size_t n);
426cefaae1SJack Meng extern size_t strlen(const char *s);
436cefaae1SJack Meng static void kinet_ntoa(char *buf, void *in, int af);
446cefaae1SJack Meng extern ib_boot_prop_t *iscsiboot_prop;
456cefaae1SJack Meng 
466cefaae1SJack Meng int  iscsi_print_bootprop	=	0;
476cefaae1SJack Meng 
486cefaae1SJack Meng #define	ISCSI_BOOTPROP_BUFLEN	256
496cefaae1SJack Meng 
50dedec472SJack Meng static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n);
51dedec472SJack Meng 
526cefaae1SJack Meng static void
iscsi_bootprop_print(int level,char * str)536cefaae1SJack Meng iscsi_bootprop_print(int level, char *str)
546cefaae1SJack Meng {
556cefaae1SJack Meng 	if (str == NULL) {
566cefaae1SJack Meng 		return;
576cefaae1SJack Meng 	}
586cefaae1SJack Meng 	if (iscsi_print_bootprop == 1) {
596cefaae1SJack Meng 		cmn_err(level, "%s", str);
606cefaae1SJack Meng 	}
616cefaae1SJack Meng }
626cefaae1SJack Meng 
636cefaae1SJack Meng static void
iscsi_print_initiator_property(ib_ini_prop_t * ibinitp)646cefaae1SJack Meng iscsi_print_initiator_property(ib_ini_prop_t *ibinitp)
656cefaae1SJack Meng {
666cefaae1SJack Meng 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
676cefaae1SJack Meng 
686cefaae1SJack Meng 	if (ibinitp == NULL) {
696cefaae1SJack Meng 		return;
706cefaae1SJack Meng 	}
716cefaae1SJack Meng 
726cefaae1SJack Meng 	if (ibinitp->ini_name != NULL) {
736cefaae1SJack Meng 		(void) sprintf(outbuf,
746cefaae1SJack Meng 		    "Initiator Name : %s\n",
756cefaae1SJack Meng 		    ibinitp->ini_name);
766cefaae1SJack Meng 		iscsi_bootprop_print(CE_CONT, outbuf);
776cefaae1SJack Meng 	}
786cefaae1SJack Meng 
796cefaae1SJack Meng 	if (ibinitp->ini_chap_name != NULL) {
806cefaae1SJack Meng 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
816cefaae1SJack Meng 		(void) sprintf(outbuf,
826cefaae1SJack Meng 		    "Initiator CHAP Name  : %s\n",
836cefaae1SJack Meng 		    ibinitp->ini_chap_name);
846cefaae1SJack Meng 
856cefaae1SJack Meng 		iscsi_bootprop_print(CE_CONT, outbuf);
866cefaae1SJack Meng 	}
876cefaae1SJack Meng }
886cefaae1SJack Meng 
896cefaae1SJack Meng static void
iscsi_print_nic_property(ib_nic_prop_t * nicp)906cefaae1SJack Meng iscsi_print_nic_property(ib_nic_prop_t *nicp)
916cefaae1SJack Meng {
926cefaae1SJack Meng 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
936cefaae1SJack Meng 	char	ipaddr[50]  =	{0};
946cefaae1SJack Meng 	int	n	    =	0;
956cefaae1SJack Meng 
966cefaae1SJack Meng 	if (nicp == NULL) {
976cefaae1SJack Meng 		return;
986cefaae1SJack Meng 	}
996cefaae1SJack Meng 
1006cefaae1SJack Meng 	kinet_ntoa(ipaddr, &nicp->nic_ip_u, nicp->sin_family);
1016cefaae1SJack Meng 	n = snprintf(outbuf, ISCSI_BOOTPROP_BUFLEN,
1026cefaae1SJack Meng 	    "Local IP addr  : %s\n", ipaddr);
1036cefaae1SJack Meng 
1046cefaae1SJack Meng 	(void) memset(ipaddr, 0, 50);
1056cefaae1SJack Meng 	kinet_ntoa(ipaddr, &nicp->nic_gw_u, nicp->sin_family);
1066cefaae1SJack Meng 	n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
1076cefaae1SJack Meng 	    "Local gateway  : %s\n", ipaddr);
1086cefaae1SJack Meng 
1096cefaae1SJack Meng 	(void) memset(ipaddr, 0, 50);
1106cefaae1SJack Meng 	kinet_ntoa(ipaddr, &nicp->nic_dhcp_u, nicp->sin_family);
1116cefaae1SJack Meng 	n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
1126cefaae1SJack Meng 	    "Local DHCP     : %s\n", ipaddr);
1136cefaae1SJack Meng 
1146cefaae1SJack Meng 	(void) snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
1156cefaae1SJack Meng 	    "Local MAC      : %02x:%02x:%02x:%02x:%02x:%02x\n",
1166cefaae1SJack Meng 	    nicp->nic_mac[0],
1176cefaae1SJack Meng 	    nicp->nic_mac[1],
1186cefaae1SJack Meng 	    nicp->nic_mac[2],
1196cefaae1SJack Meng 	    nicp->nic_mac[3],
1206cefaae1SJack Meng 	    nicp->nic_mac[4],
1216cefaae1SJack Meng 	    nicp->nic_mac[5]);
1226cefaae1SJack Meng 
1236cefaae1SJack Meng 	iscsi_bootprop_print(CE_CONT, outbuf);
1246cefaae1SJack Meng }
1256cefaae1SJack Meng 
1266cefaae1SJack Meng static void
iscsi_print_tgt_property(ib_tgt_prop_t * itgtp)1276cefaae1SJack Meng iscsi_print_tgt_property(ib_tgt_prop_t *itgtp)
1286cefaae1SJack Meng {
1296cefaae1SJack Meng 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
1306cefaae1SJack Meng 	char	ipaddr[50]  =	{0};
1316cefaae1SJack Meng 
1326cefaae1SJack Meng 	if (itgtp == NULL) {
1336cefaae1SJack Meng 		return;
1346cefaae1SJack Meng 	}
1356cefaae1SJack Meng 
1366cefaae1SJack Meng 	if (itgtp->tgt_name != NULL) {
1376cefaae1SJack Meng 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
1386cefaae1SJack Meng 		(void) sprintf(outbuf,
1396cefaae1SJack Meng 		    "Target Name    : %s\n",
1406cefaae1SJack Meng 		    itgtp->tgt_name);
1416cefaae1SJack Meng 		iscsi_bootprop_print(CE_CONT, outbuf);
1426cefaae1SJack Meng 	}
1436cefaae1SJack Meng 
1446cefaae1SJack Meng 	kinet_ntoa(ipaddr, &itgtp->tgt_ip_u, itgtp->sin_family);
1456cefaae1SJack Meng 	(void) sprintf(outbuf,
1466cefaae1SJack Meng 	    "Target IP      : %s\n"
1476cefaae1SJack Meng 	    "Target Port    : %d\n"
1486cefaae1SJack Meng 	    "Boot LUN       : %02x%02x-%02x%02x-%02x%02x-%02x%02x\n",
1496cefaae1SJack Meng 	    ipaddr,
1506cefaae1SJack Meng 	    itgtp->tgt_port,
1516cefaae1SJack Meng 	    itgtp->tgt_boot_lun[0],
1526cefaae1SJack Meng 	    itgtp->tgt_boot_lun[1],
1536cefaae1SJack Meng 	    itgtp->tgt_boot_lun[2],
1546cefaae1SJack Meng 	    itgtp->tgt_boot_lun[3],
1556cefaae1SJack Meng 	    itgtp->tgt_boot_lun[4],
1566cefaae1SJack Meng 	    itgtp->tgt_boot_lun[5],
1576cefaae1SJack Meng 	    itgtp->tgt_boot_lun[6],
1586cefaae1SJack Meng 	    itgtp->tgt_boot_lun[7]);
1596cefaae1SJack Meng 	iscsi_bootprop_print(CE_CONT, outbuf);
1606cefaae1SJack Meng 
1616cefaae1SJack Meng 	if (itgtp->tgt_chap_name != NULL) {
1626cefaae1SJack Meng 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
1636cefaae1SJack Meng 		(void) sprintf(outbuf,
1646cefaae1SJack Meng 		    "CHAP Name      : %s\n",
1656cefaae1SJack Meng 		    itgtp->tgt_chap_name);
1666cefaae1SJack Meng 		iscsi_bootprop_print(CE_CONT, outbuf);
1676cefaae1SJack Meng 	}
1686cefaae1SJack Meng }
1696cefaae1SJack Meng 
1706cefaae1SJack Meng void
iscsi_print_boot_property()1716cefaae1SJack Meng iscsi_print_boot_property()
1726cefaae1SJack Meng {
1736cefaae1SJack Meng 	if (iscsiboot_prop == NULL) {
1746cefaae1SJack Meng 		return;
1756cefaae1SJack Meng 	}
1766cefaae1SJack Meng 
1776cefaae1SJack Meng 	iscsi_print_initiator_property(
1786cefaae1SJack Meng 	    &iscsiboot_prop->boot_init);
1796cefaae1SJack Meng 
1806cefaae1SJack Meng 	iscsi_print_nic_property(&iscsiboot_prop->boot_nic);
1816cefaae1SJack Meng 
1826cefaae1SJack Meng 	iscsi_print_tgt_property(&iscsiboot_prop->boot_tgt);
1836cefaae1SJack Meng }
1846cefaae1SJack Meng 
1856cefaae1SJack Meng void
iscsi_boot_free_ini(ib_ini_prop_t * init)1866cefaae1SJack Meng iscsi_boot_free_ini(ib_ini_prop_t *init)
1876cefaae1SJack Meng {
1886cefaae1SJack Meng 	if (init == NULL) {
1896cefaae1SJack Meng 		return;
1906cefaae1SJack Meng 	}
1916cefaae1SJack Meng 
1926cefaae1SJack Meng 	if (init->ini_name != NULL) {
193dedec472SJack Meng 		kmem_free(init->ini_name, init->ini_name_len);
1946cefaae1SJack Meng 		init->ini_name = NULL;
195dedec472SJack Meng 		init->ini_name_len = 0;
1966cefaae1SJack Meng 	}
1976cefaae1SJack Meng 	if (init->ini_chap_name != NULL) {
1986cefaae1SJack Meng 		kmem_free(init->ini_chap_name,
199dedec472SJack Meng 		    init->ini_chap_name_len);
2006cefaae1SJack Meng 		init->ini_chap_name = NULL;
201dedec472SJack Meng 		init->ini_chap_name_len = 0;
2026cefaae1SJack Meng 	}
2036cefaae1SJack Meng 	if (init->ini_chap_sec != NULL) {
2046cefaae1SJack Meng 		kmem_free(init->ini_chap_sec,
205dedec472SJack Meng 		    init->ini_chap_sec_len);
2066cefaae1SJack Meng 		init->ini_chap_sec = NULL;
207dedec472SJack Meng 		init->ini_chap_sec_len = 0;
2086cefaae1SJack Meng 	}
2096cefaae1SJack Meng }
2106cefaae1SJack Meng 
2116cefaae1SJack Meng void
iscsi_boot_free_tgt(ib_tgt_prop_t * target)2126cefaae1SJack Meng iscsi_boot_free_tgt(ib_tgt_prop_t *target)
2136cefaae1SJack Meng {
2146cefaae1SJack Meng 	if (target == NULL) {
2156cefaae1SJack Meng 		return;
2166cefaae1SJack Meng 	}
2176cefaae1SJack Meng 
2186cefaae1SJack Meng 	if (target->tgt_name != NULL) {
2196cefaae1SJack Meng 		kmem_free(target->tgt_name,
220dedec472SJack Meng 		    target->tgt_name_len);
2216cefaae1SJack Meng 		target->tgt_name = NULL;
222dedec472SJack Meng 		target->tgt_name_len = 0;
2236cefaae1SJack Meng 	}
2246cefaae1SJack Meng 	if (target->tgt_chap_name != NULL) {
2256cefaae1SJack Meng 		kmem_free(target->tgt_chap_name,
226dedec472SJack Meng 		    target->tgt_chap_name_len);
2276cefaae1SJack Meng 		target->tgt_chap_name = NULL;
228dedec472SJack Meng 		target->tgt_chap_name_len = 0;
2296cefaae1SJack Meng 	}
2306cefaae1SJack Meng 	if (target->tgt_chap_sec != NULL) {
2316cefaae1SJack Meng 		kmem_free(target->tgt_chap_sec,
232dedec472SJack Meng 		    target->tgt_chap_sec_len);
2336cefaae1SJack Meng 		target->tgt_chap_sec = NULL;
234dedec472SJack Meng 		target->tgt_chap_sec_len = 0;
235dedec472SJack Meng 	}
236dedec472SJack Meng 	if (target->tgt_boot_par != NULL) {
237dedec472SJack Meng 		kmem_free(target->tgt_boot_par,
238dedec472SJack Meng 		    target->tgt_boot_par_len);
239dedec472SJack Meng 		target->tgt_boot_par = NULL;
240dedec472SJack Meng 		target->tgt_boot_par_len = 0;
2416cefaae1SJack Meng 	}
2426cefaae1SJack Meng }
2436cefaae1SJack Meng 
2446cefaae1SJack Meng /*
2456cefaae1SJack Meng  * Free the memory used by boot property.
2466cefaae1SJack Meng  */
2476cefaae1SJack Meng void
iscsi_boot_prop_free()2486cefaae1SJack Meng iscsi_boot_prop_free()
2496cefaae1SJack Meng {
2506cefaae1SJack Meng 	ib_boot_prop_t	*tmp;
2516cefaae1SJack Meng 
2526cefaae1SJack Meng 	if (iscsiboot_prop == NULL) {
2536cefaae1SJack Meng 		return;
2546cefaae1SJack Meng 	}
2556cefaae1SJack Meng 	tmp = iscsiboot_prop;
2566cefaae1SJack Meng 	iscsiboot_prop = NULL;
2576cefaae1SJack Meng 	iscsi_boot_free_ini(&(tmp->boot_init));
2586cefaae1SJack Meng 	iscsi_boot_free_tgt(&(tmp->boot_tgt));
2596cefaae1SJack Meng }
2606cefaae1SJack Meng 
2616cefaae1SJack Meng static void
kinet_ntoa(char * buf,void * in,int af)2626cefaae1SJack Meng kinet_ntoa(char *buf, void *in, int af)
2636cefaae1SJack Meng {
2646cefaae1SJack Meng 	unsigned char   *p =    NULL;
2656cefaae1SJack Meng 	int	i = 0;
2666cefaae1SJack Meng 
2676cefaae1SJack Meng 	if (buf == NULL || in == NULL) {
2686cefaae1SJack Meng 		return;
2696cefaae1SJack Meng 	}
2706cefaae1SJack Meng 	p = (unsigned char *)in;
2716cefaae1SJack Meng 	if (af == AF_INET) {
2726cefaae1SJack Meng 		(void) sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
2736cefaae1SJack Meng 	} else {
2746cefaae1SJack Meng 		for (i = 0; i < 14; i = i + 2) {
2756cefaae1SJack Meng 			(void) sprintf(buf, "%02x%02x:", p[i], p[i+1]);
2766cefaae1SJack Meng 			buf = buf + 5;
2776cefaae1SJack Meng 		}
2786cefaae1SJack Meng 		(void) sprintf(buf, "%02x%02x", p[i], p[i+1]);
2796cefaae1SJack Meng 	}
2806cefaae1SJack Meng }
281dedec472SJack Meng 
282dedec472SJack Meng #ifndef	BO_MAXOBJNAME
283dedec472SJack Meng #define	BO_MAXOBJNAME	256
284dedec472SJack Meng #endif
285dedec472SJack Meng 
286dedec472SJack Meng #ifndef ISCSI_BOOT_ISID
287dedec472SJack Meng #define	ISCSI_BOOT_ISID	"0000"
288dedec472SJack Meng #endif
289dedec472SJack Meng 
290dedec472SJack Meng /*
291dedec472SJack Meng  * Generate the 'ssd' bootpath of an iSCSI boot device
292dedec472SJack Meng  * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
293dedec472SJack Meng  */
294dedec472SJack Meng void
get_iscsi_bootpath_vhci(char * bootpath)295dedec472SJack Meng get_iscsi_bootpath_vhci(char *bootpath)
296dedec472SJack Meng {
297dedec472SJack Meng 	uint16_t	*lun_num;
298dedec472SJack Meng 
299dedec472SJack Meng 	if (iscsiboot_prop == NULL)
300dedec472SJack Meng 		ld_ib_prop();
301dedec472SJack Meng 	if (iscsiboot_prop == NULL)
302dedec472SJack Meng 		return;
303dedec472SJack Meng 	lun_num = (uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
304dedec472SJack Meng 	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/ssd@%s%s%04X,%d:%s",
305dedec472SJack Meng 	    ISCSI_BOOT_ISID, iscsiboot_prop->boot_tgt.tgt_name,
306dedec472SJack Meng 	    iscsiboot_prop->boot_tgt.tgt_tpgt, lun_num[0],
307dedec472SJack Meng 	    iscsiboot_prop->boot_tgt.tgt_boot_par);
308dedec472SJack Meng }
309dedec472SJack Meng 
310dedec472SJack Meng /*
311dedec472SJack Meng  * Generate the 'disk' bootpath of an iSCSI boot device
312dedec472SJack Meng  * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
313dedec472SJack Meng  */
314dedec472SJack Meng void
get_iscsi_bootpath_phy(char * bootpath)315dedec472SJack Meng get_iscsi_bootpath_phy(char *bootpath)
316dedec472SJack Meng {
317dedec472SJack Meng 	uint16_t	lun_num		= 0;
318dedec472SJack Meng 	uchar_t		replaced_name[BO_MAXOBJNAME] = {0};
319dedec472SJack Meng 
320dedec472SJack Meng 	if (iscsiboot_prop == NULL)
321dedec472SJack Meng 		ld_ib_prop();
322dedec472SJack Meng 	if (iscsiboot_prop == NULL)
323dedec472SJack Meng 		return;
324dedec472SJack Meng 	if (replace_sp_c(replaced_name, iscsiboot_prop->boot_tgt.tgt_name,
325dedec472SJack Meng 	    iscsiboot_prop->boot_tgt.tgt_name_len) != 0) {
326dedec472SJack Meng 		return;
327dedec472SJack Meng 	}
328dedec472SJack Meng 	lun_num = *(uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
329dedec472SJack Meng 	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/disk@%s%s%04X,%d:%s",
330dedec472SJack Meng 	    ISCSI_BOOT_ISID, replaced_name, iscsiboot_prop->boot_tgt.tgt_tpgt,
331dedec472SJack Meng 	    lun_num, iscsiboot_prop->boot_tgt.tgt_boot_par);
332dedec472SJack Meng }
333dedec472SJack Meng 
replace_sp_c(unsigned char * dst,unsigned char * source,size_t n)334dedec472SJack Meng static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n)
335dedec472SJack Meng {
336dedec472SJack Meng 	unsigned char	*p	= NULL;
337dedec472SJack Meng 	int		i	= 0;
338dedec472SJack Meng 
339dedec472SJack Meng 	if (source == NULL || dst == NULL || n == 0) {
340dedec472SJack Meng 		return (-1);
341dedec472SJack Meng 	}
342dedec472SJack Meng 
343dedec472SJack Meng 	for (p = source; *p != '\0'; p++, i++) {
344dedec472SJack Meng 		if (i >= n) {
345dedec472SJack Meng 			return (-1);
346dedec472SJack Meng 		}
347dedec472SJack Meng 		switch (*p) {
348dedec472SJack Meng 		case ':':
349dedec472SJack Meng 			*dst = '%';
350dedec472SJack Meng 			dst++;
351dedec472SJack Meng 			*dst = '3';
352dedec472SJack Meng 			dst++;
353dedec472SJack Meng 			*dst = 'A';
354dedec472SJack Meng 			dst++;
355dedec472SJack Meng 			break;
356dedec472SJack Meng 		case ' ':
357dedec472SJack Meng 			*dst = '%';
358dedec472SJack Meng 			dst++;
359dedec472SJack Meng 			*dst = '2';
360dedec472SJack Meng 			dst++;
361dedec472SJack Meng 			*dst = '0';
362dedec472SJack Meng 			dst++;
363dedec472SJack Meng 			break;
364dedec472SJack Meng 		case '@':
365dedec472SJack Meng 			*dst = '%';
366dedec472SJack Meng 			dst++;
367dedec472SJack Meng 			*dst = '4';
368dedec472SJack Meng 			dst++;
369dedec472SJack Meng 			*dst = '0';
370dedec472SJack Meng 			dst++;
371dedec472SJack Meng 			break;
372dedec472SJack Meng 		case '/':
373dedec472SJack Meng 			*dst = '%';
374dedec472SJack Meng 			dst++;
375dedec472SJack Meng 			*dst = '2';
376dedec472SJack Meng 			dst++;
377dedec472SJack Meng 			*dst = 'F';
378dedec472SJack Meng 			dst++;
379dedec472SJack Meng 			break;
380dedec472SJack Meng 		default:
381dedec472SJack Meng 			*dst = *p;
382dedec472SJack Meng 			dst++;
383dedec472SJack Meng 		}
384dedec472SJack Meng 	}
385dedec472SJack Meng 	*dst = '\0';
386dedec472SJack Meng 
387dedec472SJack Meng 	return (0);
388dedec472SJack Meng }
389