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