xref: /titanic_54/usr/src/lib/libinetutil/common/ifspec.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This file contains a routine used to validate a ifconfig-style interface
31*7c478bd9Sstevel@tonic-gate  * specification
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <alloca.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <string.h>
39*7c478bd9Sstevel@tonic-gate #include <libinetutil.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  * Given a token with a logical unit spec, return the logical unit converted
43*7c478bd9Sstevel@tonic-gate  * to a uint_t.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  * Returns: 0 for success, nonzero if an error occurred. errno is set if
46*7c478bd9Sstevel@tonic-gate  * necessary.
47*7c478bd9Sstevel@tonic-gate  */
48*7c478bd9Sstevel@tonic-gate static int
49*7c478bd9Sstevel@tonic-gate getlun(const char *bp, int bpsize, uint_t *lun)
50*7c478bd9Sstevel@tonic-gate {
51*7c478bd9Sstevel@tonic-gate 	char	*ep = (char *)&bp[bpsize - 1];
52*7c478bd9Sstevel@tonic-gate 	char	*sp = strchr(bp, ':'), *tp;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate 	/* A logical unit spec looks like: <token>:<unsigned int>\0 */
55*7c478bd9Sstevel@tonic-gate 	if (isdigit(*bp) || !isdigit(*ep) || sp == NULL ||
56*7c478bd9Sstevel@tonic-gate 	    strchr(sp + 1, ':') != NULL) {
57*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
58*7c478bd9Sstevel@tonic-gate 		return (-1);
59*7c478bd9Sstevel@tonic-gate 	}
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	*sp++ = '\0';
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate 	/* Lun must be all digits */
64*7c478bd9Sstevel@tonic-gate 	for (tp = sp; tp < ep && isdigit(*tp); tp++)
65*7c478bd9Sstevel@tonic-gate 		/* Null body */;
66*7c478bd9Sstevel@tonic-gate 	if (tp != ep) {
67*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
68*7c478bd9Sstevel@tonic-gate 		return (-1);
69*7c478bd9Sstevel@tonic-gate 	}
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	*lun = atoi(sp);
72*7c478bd9Sstevel@tonic-gate 	return (0);
73*7c478bd9Sstevel@tonic-gate }
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * Given a single token ending with a ppa spec, return the ppa spec converted
77*7c478bd9Sstevel@tonic-gate  * to a uint_t.
78*7c478bd9Sstevel@tonic-gate  *
79*7c478bd9Sstevel@tonic-gate  * Returns: 0 for success, nonzero if an error occurred. errno is set if
80*7c478bd9Sstevel@tonic-gate  * necessary.
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate static int
83*7c478bd9Sstevel@tonic-gate getppa(const char *bp, int bpsize, uint_t *ppa)
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate 	char	*ep = (char *)&bp[bpsize - 1];
86*7c478bd9Sstevel@tonic-gate 	char	*tp;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	if (isdigit(*bp) || !isdigit(*ep)) {
89*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
90*7c478bd9Sstevel@tonic-gate 		return (-1);
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	for (tp = ep; tp >= bp && isdigit(*tp); tp--)
94*7c478bd9Sstevel@tonic-gate 		/* Null body */;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if (*tp == '.' || *tp == ':') {
97*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
98*7c478bd9Sstevel@tonic-gate 		return (-1);
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	*ppa = atoi(tp + 1);
102*7c478bd9Sstevel@tonic-gate 	return (0);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * Given an ifconfig-style inet relative-path interface specification
107*7c478bd9Sstevel@tonic-gate  * (e.g: hme0.foo.ip.udp:2), validate its form and decompose the contents
108*7c478bd9Sstevel@tonic-gate  * into a dynamically allocated ifspec_t.
109*7c478bd9Sstevel@tonic-gate  *
110*7c478bd9Sstevel@tonic-gate  * Returns ifspec_t for success, NULL pointer if spec is malformed.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate boolean_t
113*7c478bd9Sstevel@tonic-gate ifparse_ifspec(const char *ifname, ifspec_t *ifsp)
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate 	char		*mp, *ep, *lp, *tp;
116*7c478bd9Sstevel@tonic-gate 	char		*ifnamecp;
117*7c478bd9Sstevel@tonic-gate 	size_t		iflen;
118*7c478bd9Sstevel@tonic-gate 	boolean_t	have_ppa = B_FALSE;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	iflen = strlen(ifname);
121*7c478bd9Sstevel@tonic-gate 	if (iflen > LIFNAMSIZ) {
122*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
123*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
124*7c478bd9Sstevel@tonic-gate 	}
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	/* snag a copy we can modify */
127*7c478bd9Sstevel@tonic-gate 	ifnamecp = alloca(iflen + 1);
128*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifnamecp, ifname, iflen + 1);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	ifsp->ifsp_lunvalid = B_FALSE;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	/*
133*7c478bd9Sstevel@tonic-gate 	 * An interface name must have the format of:
134*7c478bd9Sstevel@tonic-gate 	 * dev[ppa][.module[.module...][ppa]][:lun]
135*7c478bd9Sstevel@tonic-gate 	 *
136*7c478bd9Sstevel@tonic-gate 	 * where only one ppa may be specified e.g. ip0.foo.tun or ip.foo.tun0
137*7c478bd9Sstevel@tonic-gate 	 *
138*7c478bd9Sstevel@tonic-gate 	 * lun - logical unit number.
139*7c478bd9Sstevel@tonic-gate 	 *
140*7c478bd9Sstevel@tonic-gate 	 * Produce substrings for each grouping, starting first with modules,
141*7c478bd9Sstevel@tonic-gate 	 * then lun, devname, and finally ppa.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	/* Any modules? */
145*7c478bd9Sstevel@tonic-gate 	mp = strchr(ifnamecp, '.');
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/* Any logical units? */
148*7c478bd9Sstevel@tonic-gate 	lp = strchr(ifnamecp, ':');
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (lp != NULL && mp != NULL && lp < mp) {
151*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
152*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	ifsp->ifsp_modcnt = 0;
156*7c478bd9Sstevel@tonic-gate 	if (mp != NULL) {
157*7c478bd9Sstevel@tonic-gate 		*mp++ = '\0';
158*7c478bd9Sstevel@tonic-gate 		if (lp != NULL)
159*7c478bd9Sstevel@tonic-gate 			*lp = '\0';
160*7c478bd9Sstevel@tonic-gate 		while (mp != NULL && ifsp->ifsp_modcnt <= IFSP_MAXMODS) {
161*7c478bd9Sstevel@tonic-gate 			if ((ep = strchr(mp, '.')) != NULL)
162*7c478bd9Sstevel@tonic-gate 				*ep++ = '\0';
163*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(ifsp->ifsp_mods[ifsp->ifsp_modcnt++],
164*7c478bd9Sstevel@tonic-gate 			    mp, LIFNAMSIZ);
165*7c478bd9Sstevel@tonic-gate 			mp = ep;
166*7c478bd9Sstevel@tonic-gate 		}
167*7c478bd9Sstevel@tonic-gate 		if (lp != NULL)
168*7c478bd9Sstevel@tonic-gate 			*lp = ':';
169*7c478bd9Sstevel@tonic-gate 		if (ifsp->ifsp_modcnt > IFSP_MAXMODS) {
170*7c478bd9Sstevel@tonic-gate 			errno = E2BIG;
171*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
172*7c478bd9Sstevel@tonic-gate 		}
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	if (lp != NULL) {
176*7c478bd9Sstevel@tonic-gate 		if (getlun(lp, strlen(lp), &ifsp->ifsp_lun) != 0)
177*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
178*7c478bd9Sstevel@tonic-gate 		ifsp->ifsp_lunvalid = B_TRUE;
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifsp->ifsp_devnm, ifnamecp, LIFNAMSIZ);
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	/* Find ppa - has to be part of devname or part of last module name */
184*7c478bd9Sstevel@tonic-gate 	/* This should be changed to require the latter of the two */
185*7c478bd9Sstevel@tonic-gate 	if (getppa(ifsp->ifsp_devnm, strlen(ifsp->ifsp_devnm),
186*7c478bd9Sstevel@tonic-gate 	    &ifsp->ifsp_ppa) == 0)
187*7c478bd9Sstevel@tonic-gate 		have_ppa = B_TRUE;
188*7c478bd9Sstevel@tonic-gate 	if (ifsp->ifsp_modcnt != 0 &&
189*7c478bd9Sstevel@tonic-gate 	    getppa(ifsp->ifsp_mods[ifsp->ifsp_modcnt - 1],
190*7c478bd9Sstevel@tonic-gate 	    strlen(ifsp->ifsp_mods[ifsp->ifsp_modcnt - 1]),
191*7c478bd9Sstevel@tonic-gate 	    &ifsp->ifsp_ppa) == 0) {
192*7c478bd9Sstevel@tonic-gate 		if (!have_ppa)
193*7c478bd9Sstevel@tonic-gate 			have_ppa = B_TRUE;
194*7c478bd9Sstevel@tonic-gate 		else
195*7c478bd9Sstevel@tonic-gate 			return (B_FALSE); /* only one please */
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 	if (!have_ppa)
198*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/* strip the ppa off of the device name if present */
201*7c478bd9Sstevel@tonic-gate 	for (tp = &ifsp->ifsp_devnm[strlen(ifsp->ifsp_devnm) - 1];
202*7c478bd9Sstevel@tonic-gate 	    tp >= ifsp->ifsp_devnm && isdigit(*tp); tp--)
203*7c478bd9Sstevel@tonic-gate 		*tp = '\0';
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
206*7c478bd9Sstevel@tonic-gate }
207