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.3 (Berkeley) 06/29/88 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 42 ns_hash(sns, hp) 43 register struct sockaddr_ns *sns; 44 struct afhash *hp; 45 { 46 register long hash = 0; 47 register u_short *s = sns->sns_addr.x_host.s_host; 48 union { 49 union ns_net net_e; 50 long long_e; 51 } net; 52 53 net.net_e = sns->sns_addr.x_net; 54 hp->afh_nethash = net.long_e; 55 hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s; 56 hp->afh_hosthash = hash; 57 } 58 59 60 ns_netmatch(sns1, sns2) 61 struct sockaddr_ns *sns1, *sns2; 62 { 63 64 return (ns_neteq(sns1->sns_addr, sns2->sns_addr)); 65 } 66 67 /* 68 * Generic internet control operations (ioctl's). 69 */ 70 /* ARGSUSED */ 71 ns_control(so, cmd, data, ifp) 72 struct socket *so; 73 int cmd; 74 caddr_t data; 75 register struct ifnet *ifp; 76 { 77 register struct ifreq *ifr = (struct ifreq *)data; 78 register struct ns_ifaddr *ia; 79 struct ifaddr *ifa; 80 struct mbuf *m; 81 82 /* 83 * Find address for this interface, if it exists. 84 */ 85 if (ifp == 0) 86 return (EADDRNOTAVAIL); 87 for (ia = ns_ifaddr; ia; ia = ia->ia_next) 88 if (ia->ia_ifp == ifp) 89 break; 90 91 switch (cmd) { 92 93 case SIOCGIFADDR: 94 if (ia == (struct ns_ifaddr *)0) 95 return (EADDRNOTAVAIL); 96 ifr->ifr_addr = ia->ia_addr; 97 return (0); 98 99 100 case SIOCGIFBRDADDR: 101 if (ia == (struct ns_ifaddr *)0) 102 return (EADDRNOTAVAIL); 103 if ((ifp->if_flags & IFF_BROADCAST) == 0) 104 return (EINVAL); 105 ifr->ifr_dstaddr = ia->ia_broadaddr; 106 return (0); 107 108 case SIOCGIFDSTADDR: 109 if (ia == (struct ns_ifaddr *)0) 110 return (EADDRNOTAVAIL); 111 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 112 return (EINVAL); 113 ifr->ifr_dstaddr = ia->ia_dstaddr; 114 return (0); 115 } 116 117 if (!suser()) 118 return (u.u_error); 119 120 switch (cmd) { 121 122 case SIOCSIFADDR: 123 case SIOCSIFDSTADDR: 124 if (ia == (struct ns_ifaddr *)0) { 125 m = m_getclr(M_WAIT, MT_IFADDR); 126 if (m == (struct mbuf *)NULL) 127 return (ENOBUFS); 128 if (ia = ns_ifaddr) { 129 for ( ; ia->ia_next; ia = ia->ia_next) 130 ; 131 ia->ia_next = mtod(m, struct ns_ifaddr *); 132 } else 133 ns_ifaddr = mtod(m, struct ns_ifaddr *); 134 ia = mtod(m, struct ns_ifaddr *); 135 if (ifa = ifp->if_addrlist) { 136 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 137 ; 138 ifa->ifa_next = (struct ifaddr *) ia; 139 } else 140 ifp->if_addrlist = (struct ifaddr *) ia; 141 ia->ia_ifp = ifp; 142 IA_SNS(ia)->sns_family = AF_NS; 143 } 144 } 145 146 switch (cmd) { 147 148 case SIOCSIFDSTADDR: 149 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 150 return (EINVAL); 151 if (ia->ia_flags & IFA_ROUTE) { 152 rtinit(&ia->ia_dstaddr, &ia->ia_addr, 153 (int)SIOCDELRT, RTF_HOST); 154 ia->ia_flags &= ~IFA_ROUTE; 155 } 156 if (ifp->if_ioctl) { 157 int error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); 158 if (error) 159 return (error); 160 } 161 ia->ia_dstaddr = ifr->ifr_dstaddr; 162 return (0); 163 164 case SIOCSIFADDR: 165 return 166 (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr)); 167 168 default: 169 if (ifp->if_ioctl == 0) 170 return (EOPNOTSUPP); 171 return ((*ifp->if_ioctl)(ifp, cmd, data)); 172 } 173 } 174 175 /* 176 * Initialize an interface's internet address 177 * and routing table entry. 178 */ 179 ns_ifinit(ifp, ia, sns) 180 register struct ifnet *ifp; 181 register struct ns_ifaddr *ia; 182 struct sockaddr_ns *sns; 183 { 184 struct sockaddr_ns netaddr; 185 register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host); 186 int s = splimp(), error; 187 188 /* 189 * The convention we shall adopt for naming is that 190 * a supplied address of zero means that "we don't care". 191 * if there is a single interface, use the address of that 192 * interface as our 6 byte host address. 193 * if there are multiple interfaces, use any address already 194 * used. 195 * 196 * If we have gotten into trouble and want to reset back to 197 * virginity, we recognize a request of the broadcast address. 198 */ 199 if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) { 200 ns_thishost = ns_zerohost; 201 splx(s); 202 return (0); 203 } 204 205 /* 206 * Delete any previous route for an old address. 207 */ 208 bzero((caddr_t)&netaddr, sizeof (netaddr)); 209 netaddr.sns_family = AF_NS; 210 netaddr.sns_addr.x_host = ns_broadhost; 211 netaddr.sns_addr.x_net = ia->ia_net; 212 if (ia->ia_flags & IFA_ROUTE) { 213 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 214 rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 215 (int)SIOCDELRT, 0); 216 } else 217 rtinit(&ia->ia_dstaddr, &ia->ia_addr, 218 (int)SIOCDELRT, RTF_HOST); 219 } 220 221 /* 222 * Set up new addresses. 223 */ 224 ia->ia_addr = *(struct sockaddr *)sns; 225 ia->ia_net = sns->sns_addr.x_net; 226 netaddr.sns_addr.x_net = ia->ia_net; 227 if (ifp->if_flags & IFF_BROADCAST) { 228 ia->ia_broadaddr = * (struct sockaddr *) &netaddr; 229 } 230 231 /* 232 * Give the interface a chance to initialize 233 * if this is its first address, 234 * and to validate the address if necessary. 235 */ 236 if (ns_hosteqnh(ns_thishost, ns_zerohost)) { 237 if (ifp->if_ioctl && 238 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 239 splx(s); 240 return (error); 241 } 242 ns_thishost = *h; 243 } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) 244 || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { 245 *h = ns_thishost; 246 if (ifp->if_ioctl && 247 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 248 splx(s); 249 return (error); 250 } 251 if (!ns_hosteqnh(ns_thishost,*h)) { 252 splx(s); 253 return (EINVAL); 254 } 255 } else { 256 splx(s); 257 return (EINVAL); 258 } 259 260 /* 261 * Add route for the network. 262 */ 263 if (ifp->if_flags & IFF_POINTOPOINT) 264 rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 265 RTF_HOST|RTF_UP); 266 else 267 rtinit(&ia->ia_broadaddr, &ia->ia_addr, (int)SIOCADDRT, 268 RTF_UP); 269 ia->ia_flags |= IFA_ROUTE; 270 return (0); 271 } 272 273 /* 274 * Return address info for specified internet network. 275 */ 276 struct ns_ifaddr * 277 ns_iaonnetof(dst) 278 register struct ns_addr *dst; 279 { 280 register struct ns_ifaddr *ia; 281 register struct ns_addr *compare; 282 register struct ifnet *ifp; 283 struct ns_ifaddr *ia_maybe = 0; 284 union ns_net net = dst->x_net; 285 286 for (ia = ns_ifaddr; ia; ia = ia->ia_next) { 287 if (ifp = ia->ia_ifp) { 288 if (ifp->if_flags & IFF_POINTOPOINT) { 289 compare = &satons_addr(ia->ia_dstaddr); 290 if (ns_hosteq(*dst, *compare)) 291 return (ia); 292 if (ns_neteqnn(net, ia->ia_net)) 293 ia_maybe = ia; 294 } else { 295 if (ns_neteqnn(net, ia->ia_net)) 296 return (ia); 297 } 298 } 299 } 300 return (ia_maybe); 301 } 302 #endif 303