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