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 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 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 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 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