1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/t_kuser.h>
28 #include <sys/netconfig.h>
29 #include <netinet/in.h>
30 #include <net/route.h>
31 #include <net/if.h>
32 #include <sys/kstr.h>
33 #include <rpc/clnt.h>
34 #include <sys/stropts.h>
35 #include <sys/socket.h>
36 #include <sys/sockio.h>
37 #include <sys/bootprops.h>
38 
39 static int
kivoid_to_sock(int af,void * source,void * dest)40 kivoid_to_sock(int af, void *source, void *dest)
41 {
42 	struct sockaddr_in  *sin    =	NULL;
43 	struct sockaddr_in6 *sin6   =	NULL;
44 
45 	if (source == NULL || dest == NULL) {
46 		return (-1);
47 	}
48 	if (af == AF_INET) {
49 		sin = (struct sockaddr_in *)dest;
50 		(void) bcopy(source, &sin->sin_addr,
51 		    sizeof (struct in_addr));
52 		sin->sin_family = af;
53 	} else if (af == AF_INET6) {
54 		sin6 = (struct sockaddr_in6 *)dest;
55 		(void) bcopy(source, &sin6->sin6_addr,
56 		    sizeof (struct in6_addr));
57 		sin6->sin6_family = af;
58 	} else {
59 		return (-1);
60 	}
61 	return (0);
62 }
63 
64 int
kdlifconfig(TIUSER * tiptr,int af,void * myIPaddr,void * mymask,struct in_addr * mybraddr,struct in_addr * gateway,char * ifname)65 kdlifconfig(TIUSER *tiptr, int af, void *myIPaddr, void *mymask,
66     struct in_addr *mybraddr, struct in_addr *gateway, char *ifname)
67 {
68 	int			rc;
69 	struct netbuf		sbuf;
70 	struct sockaddr_in	sin;
71 	struct sockaddr_in6	sin6;
72 	struct rtentry		route;
73 	struct sockaddr_in	*rt_sin;
74 
75 	if (myIPaddr == NULL || mymask == NULL) {
76 		return (-1);
77 	}
78 
79 	if (af == AF_INET) {
80 		rc = kivoid_to_sock(af, mymask, &sin);
81 		if (rc != 0) {
82 			return (rc);
83 		}
84 		sbuf.buf = (caddr_t)&sin;
85 		sbuf.maxlen = sbuf.len = sizeof (sin);
86 	} else {
87 		rc = kivoid_to_sock(af, mymask, &sin6);
88 		if (rc != 0) {
89 			return (rc);
90 		}
91 		sbuf.buf = (caddr_t)&sin6;
92 		sbuf.maxlen = sbuf.len = sizeof (sin6);
93 	}
94 	if (rc = kifioctl(tiptr, SIOCSLIFNETMASK, &sbuf, ifname)) {
95 		return (rc);
96 	}
97 
98 	if (af == AF_INET) {
99 		rc = kivoid_to_sock(af, myIPaddr, &sin);
100 		if (rc != 0) {
101 			return (rc);
102 		}
103 		sbuf.buf = (caddr_t)&sin;
104 		sbuf.maxlen = sbuf.len = sizeof (sin);
105 	} else {
106 		rc = kivoid_to_sock(af, myIPaddr, &sin6);
107 		if (rc != 0) {
108 			return (rc);
109 		}
110 		sbuf.buf = (caddr_t)&sin6;
111 		sbuf.maxlen = sbuf.len = sizeof (sin6);
112 	}
113 
114 	if (rc = kifioctl(tiptr, SIOCSLIFADDR, &sbuf, ifname)) {
115 		return (rc);
116 	}
117 	/*
118 	 * Only IPv4 has brocadcast address.
119 	 */
120 	if (af == AF_INET && mybraddr != NULL) {
121 		if (mybraddr->s_addr != INADDR_BROADCAST) {
122 			rc = kivoid_to_sock(af, mybraddr, &sin);
123 			if (rc != 0) {
124 				return (rc);
125 			}
126 			sbuf.buf = (caddr_t)&sin;
127 			sbuf.maxlen = sbuf.len = sizeof (sin);
128 			if (rc = kifioctl(tiptr, SIOCSLIFBRDADDR, &sbuf,
129 			    ifname)) {
130 				return (rc);
131 			}
132 		}
133 	}
134 
135 	/*
136 	 * Now turn on the interface.
137 	 */
138 	if (rc = ksetifflags(tiptr, IFF_UP, ifname)) {
139 		return (rc);
140 	}
141 
142 	/*
143 	 * Set the default gateway.
144 	 */
145 	if (af == AF_INET && gateway != NULL) {
146 		(void) memset(&route, 0, sizeof (route));
147 		rt_sin = (struct sockaddr_in *)&route.rt_dst;
148 		rt_sin->sin_family = AF_INET;
149 
150 		rt_sin = (struct sockaddr_in *)&route.rt_gateway;
151 		rt_sin->sin_addr.s_addr = gateway->s_addr;
152 		route.rt_flags = RTF_GATEWAY | RTF_UP;
153 		sbuf.buf = (caddr_t)&route;
154 		sbuf.maxlen = sbuf.len = sizeof (route);
155 		if (rc = kifioctl(tiptr, SIOCADDRT, &sbuf, ifname)) {
156 			return (rc);
157 		}
158 	}
159 	return (0);
160 }
161 
162 int
kifioctl(TIUSER * tiptr,int cmd,struct netbuf * nbuf,char * ifname)163 kifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf, char *ifname)
164 {
165 	struct strioctl	    iocb;
166 	struct lifreq	    lifr;
167 	vnode_t		    *vp	    =	NULL;
168 	char		    *buf    =	NULL;
169 	int		    rc	    =	0;
170 
171 	(void) memset(&lifr, 0, sizeof (lifr));
172 	/*
173 	 * Now do the one requested.
174 	 */
175 	if (nbuf->len) {
176 		if (nbuf->len == sizeof (struct rtentry)) {
177 			if (cmd != SIOCADDRT) {
178 				return (-1);
179 			}
180 			/*
181 			 * Set up gateway parameters.
182 			 */
183 			iocb.ic_len = nbuf->len;
184 			iocb.ic_dp = nbuf->buf;
185 		} else {
186 			if (nbuf->len != sizeof (struct sockaddr_in) &&
187 			    nbuf->len != sizeof (struct sockaddr_in6)) {
188 				return (-1);
189 			}
190 			buf = (char *)&lifr.lifr_addr;
191 			bcopy(nbuf->buf, buf, nbuf->len);
192 			iocb.ic_len = sizeof (lifr);
193 			iocb.ic_dp = (caddr_t)&lifr;
194 		}
195 	} else {
196 		iocb.ic_len = sizeof (lifr);
197 		iocb.ic_dp = (caddr_t)&lifr;
198 	}
199 	(void) strncpy((caddr_t)&lifr.lifr_name, ifname,
200 	    sizeof (lifr.lifr_name));
201 	iocb.ic_cmd = cmd;
202 	iocb.ic_timout = 0;
203 
204 	vp = tiptr->fp->f_vnode;
205 	rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
206 	if (rc) {
207 		return (rc);
208 	}
209 
210 	return (0);
211 }
212 
213 int
ksetifflags(TIUSER * tiptr,uint_t value,char * ifname)214 ksetifflags(TIUSER *tiptr, uint_t value, char *ifname)
215 {
216 	int rc;
217 	struct strioctl iocb;
218 	struct lifreq lifr;
219 
220 	if (ifname == NULL) {
221 		return (-1);
222 	}
223 
224 	(void) memset(&lifr, 0, sizeof (lifr));
225 
226 	(void) strncpy((caddr_t)&lifr.lifr_name, ifname,
227 	    sizeof (lifr.lifr_name));
228 	iocb.ic_cmd = SIOCGLIFFLAGS;
229 	iocb.ic_timout = 0;
230 	iocb.ic_len = sizeof (lifr);
231 	iocb.ic_dp = (caddr_t)&lifr;
232 	if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
233 		return (rc);
234 
235 	lifr.lifr_flags |= value;
236 	iocb.ic_cmd = SIOCSLIFFLAGS;
237 	return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
238 }
239