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