1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ns.c 7.6 (Berkeley) 05/05/89 18 */ 19 20 #include "param.h" 21 #include "mbuf.h" 22 #include "ioctl.h" 23 #include "protosw.h" 24 #include "socket.h" 25 #include "socketvar.h" 26 #include "user.h" 27 28 29 #include "../net/if.h" 30 #include "../net/route.h" 31 #include "../net/af.h" 32 33 #include "ns.h" 34 #include "ns_if.h" 35 36 #ifdef NS 37 38 struct ns_ifaddr *ns_ifaddr; 39 int ns_interfaces; 40 extern struct sockaddr_ns ns_netmask, ns_hostmask; 41 42 /* 43 * Generic internet control operations (ioctl's). 44 */ 45 /* ARGSUSED */ 46 ns_control(so, cmd, data, ifp) 47 struct socket *so; 48 int cmd; 49 caddr_t data; 50 register struct ifnet *ifp; 51 { 52 register struct ifreq *ifr = (struct ifreq *)data; 53 register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data; 54 register struct ns_ifaddr *ia; 55 struct ifaddr *ifa; 56 struct ns_ifaddr *oia; 57 struct mbuf *m; 58 int error, dstIsNew, hostIsNew; 59 60 /* 61 * Find address for this interface, if it exists. 62 */ 63 if (ifp == 0) 64 return (EADDRNOTAVAIL); 65 for (ia = ns_ifaddr; ia; ia = ia->ia_next) 66 if (ia->ia_ifp == ifp) 67 break; 68 69 switch (cmd) { 70 71 case SIOCGIFADDR: 72 if (ia == (struct ns_ifaddr *)0) 73 return (EADDRNOTAVAIL); 74 *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr; 75 return (0); 76 77 78 case SIOCGIFBRDADDR: 79 if (ia == (struct ns_ifaddr *)0) 80 return (EADDRNOTAVAIL); 81 if ((ifp->if_flags & IFF_BROADCAST) == 0) 82 return (EINVAL); 83 *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 84 return (0); 85 86 case SIOCGIFDSTADDR: 87 if (ia == (struct ns_ifaddr *)0) 88 return (EADDRNOTAVAIL); 89 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 90 return (EINVAL); 91 *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 92 return (0); 93 } 94 95 if (error = suser(u.u_cred, &u.u_acflag)) 96 return (error); 97 98 switch (cmd) { 99 case SIOCAIFADDR: 100 case SIOCDIFADDR: 101 if (ifra->ifra_addr.sns_family == AF_NS) 102 for (oia = ia; ia; ia = ia->ia_next) { 103 if (ia->ia_ifp == ifp && 104 ns_neteq(ia->ia_addr.sns_addr, 105 ifra->ifra_addr.sns_addr)) 106 break; 107 } 108 if (cmd == SIOCDIFADDR && ia == 0) 109 return (EADDRNOTAVAIL); 110 /* FALLTHROUGH */ 111 112 case SIOCSIFADDR: 113 case SIOCSIFDSTADDR: 114 if (ia == (struct ns_ifaddr *)0) { 115 m = m_getclr(M_WAIT, MT_IFADDR); 116 if (m == (struct mbuf *)NULL) 117 return (ENOBUFS); 118 if (ia = ns_ifaddr) { 119 for ( ; ia->ia_next; ia = ia->ia_next) 120 ; 121 ia->ia_next = mtod(m, struct ns_ifaddr *); 122 } else 123 ns_ifaddr = mtod(m, struct ns_ifaddr *); 124 ia = mtod(m, struct ns_ifaddr *); 125 if (ifa = ifp->if_addrlist) { 126 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 127 ; 128 ifa->ifa_next = (struct ifaddr *) ia; 129 } else 130 ifp->if_addrlist = (struct ifaddr *) ia; 131 ia->ia_ifp = ifp; 132 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 133 134 ia->ia_ifa.ifa_netmask = 135 (struct sockaddr *)&ns_netmask; 136 137 ia->ia_ifa.ifa_dstaddr = 138 (struct sockaddr *)&ia->ia_dstaddr; 139 if (ifp->if_flags & IFF_BROADCAST) { 140 ia->ia_broadaddr.sns_family = AF_NS; 141 ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr); 142 ia->ia_broadaddr.sns_addr.x_host = ns_broadhost; 143 } 144 ns_interfaces++; 145 } 146 } 147 148 switch (cmd) { 149 int error; 150 151 case SIOCSIFDSTADDR: 152 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 153 return (EINVAL); 154 if (ia->ia_flags & IFA_ROUTE) { 155 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 156 ia->ia_flags &= ~IFA_ROUTE; 157 } 158 if (ifp->if_ioctl) { 159 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); 160 if (error) 161 return (error); 162 } 163 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 164 return (0); 165 166 case SIOCSIFADDR: 167 return (ns_ifinit(ifp, ia, 168 (struct sockaddr_ns *)&ifr->ifr_addr, 1)); 169 170 case SIOCDIFADDR: 171 ns_ifscrub(ifp, ia); 172 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) 173 ifp->if_addrlist = ifa->ifa_next; 174 else { 175 while (ifa->ifa_next && 176 (ifa->ifa_next != (struct ifaddr *)ia)) 177 ifa = ifa->ifa_next; 178 if (ifa->ifa_next) 179 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; 180 else 181 printf("Couldn't unlink nsifaddr from ifp\n"); 182 } 183 oia = ia; 184 if (oia == (ia = ns_ifaddr)) { 185 ns_ifaddr = ia->ia_next; 186 } else { 187 while (ia->ia_next && (ia->ia_next != oia)) { 188 ia = ia->ia_next; 189 } 190 if (ia->ia_next) 191 ia->ia_next = oia->ia_next; 192 else 193 printf("Didn't unlink nsifadr from list\n"); 194 } 195 (void) m_free(dtom(oia)); 196 if (0 == --ns_interfaces) { 197 /* 198 * We reset to virginity and start all over again 199 */ 200 ns_thishost = ns_zerohost; 201 } 202 return (0); 203 204 case SIOCAIFADDR: 205 dstIsNew = 0; hostIsNew = 1; 206 if (ia->ia_addr.sns_family == AF_NS) { 207 if (ifra->ifra_addr.sns_len == 0) { 208 ifra->ifra_addr = ia->ia_addr; 209 hostIsNew = 0; 210 } else if (ns_neteq(ifra->ifra_addr.sns_addr, 211 ia->ia_addr.sns_addr)) 212 hostIsNew = 0; 213 } 214 if ((ifp->if_flags & IFF_POINTOPOINT) && 215 (ifra->ifra_dstaddr.sns_family == AF_NS)) { 216 if (hostIsNew == 0) 217 ns_ifscrub(ifp, ia); 218 ia->ia_dstaddr = ifra->ifra_dstaddr; 219 dstIsNew = 1; 220 } 221 if (ifra->ifra_addr.sns_family == AF_NS && 222 (hostIsNew || dstIsNew)) 223 error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0); 224 return (error); 225 226 default: 227 if (ifp->if_ioctl == 0) 228 return (EOPNOTSUPP); 229 return ((*ifp->if_ioctl)(ifp, cmd, data)); 230 } 231 } 232 233 /* 234 * Delete any previous route for an old address. 235 */ 236 ns_ifscrub(ifp, ia) 237 register struct ifnet *ifp; 238 register struct ns_ifaddr *ia; 239 { 240 if (ia->ia_flags & IFA_ROUTE) { 241 if (ifp->if_flags & IFF_POINTOPOINT) { 242 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 243 } else 244 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 245 ia->ia_flags &= ~IFA_ROUTE; 246 } 247 } 248 /* 249 * Initialize an interface's internet address 250 * and routing table entry. 251 */ 252 ns_ifinit(ifp, ia, sns, scrub) 253 register struct ifnet *ifp; 254 register struct ns_ifaddr *ia; 255 register struct sockaddr_ns *sns; 256 { 257 struct sockaddr_ns oldaddr; 258 register union ns_host *h = &ia->ia_addr.sns_addr.x_host; 259 int s = splimp(), error; 260 261 /* 262 * Set up new addresses. 263 */ 264 oldaddr = ia->ia_addr; 265 ia->ia_addr = *sns; 266 /* 267 * The convention we shall adopt for naming is that 268 * a supplied address of zero means that "we don't care". 269 * if there is a single interface, use the address of that 270 * interface as our 6 byte host address. 271 * if there are multiple interfaces, use any address already 272 * used. 273 * 274 * Give the interface a chance to initialize 275 * if this is its first address, 276 * and to validate the address if necessary. 277 */ 278 if (ns_hosteqnh(ns_thishost, ns_zerohost)) { 279 if (ifp->if_ioctl && 280 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 281 ia->ia_addr = oldaddr; 282 splx(s); 283 return (error); 284 } 285 ns_thishost = *h; 286 } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) 287 || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { 288 *h = ns_thishost; 289 if (ifp->if_ioctl && 290 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 291 ia->ia_addr = oldaddr; 292 splx(s); 293 return (error); 294 } 295 if (!ns_hosteqnh(ns_thishost,*h)) { 296 ia->ia_addr = oldaddr; 297 splx(s); 298 return (EINVAL); 299 } 300 } else { 301 ia->ia_addr = oldaddr; 302 splx(s); 303 return (EINVAL); 304 } 305 /* 306 * Add route for the network. 307 */ 308 if (scrub) { 309 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 310 ns_ifscrub(ifp, ia); 311 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 312 } 313 if (ifp->if_flags & IFF_POINTOPOINT) 314 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 315 else { 316 ia->ia_broadaddr.sns_addr.x_net = ia->ia_net; 317 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 318 } 319 ia->ia_flags |= IFA_ROUTE; 320 return (0); 321 } 322 323 /* 324 * Return address info for specified internet network. 325 */ 326 struct ns_ifaddr * 327 ns_iaonnetof(dst) 328 register struct ns_addr *dst; 329 { 330 register struct ns_ifaddr *ia; 331 register struct ns_addr *compare; 332 register struct ifnet *ifp; 333 struct ns_ifaddr *ia_maybe = 0; 334 union ns_net net = dst->x_net; 335 336 for (ia = ns_ifaddr; ia; ia = ia->ia_next) { 337 if (ifp = ia->ia_ifp) { 338 if (ifp->if_flags & IFF_POINTOPOINT) { 339 compare = &satons_addr(ia->ia_dstaddr); 340 if (ns_hosteq(*dst, *compare)) 341 return (ia); 342 if (ns_neteqnn(net, ia->ia_net)) 343 ia_maybe = ia; 344 } else { 345 if (ns_neteqnn(net, ia->ia_net)) 346 return (ia); 347 } 348 } 349 } 350 return (ia_maybe); 351 } 352 #endif 353