1 /* 2 * Copyright (c) 1985 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)ns_ip.c 6.11 (Berkeley) 11/09/85 7 */ 8 9 /* 10 * Software interface driver for encapsulating ns in ip. 11 */ 12 13 #ifdef NSIP 14 #include "param.h" 15 #include "systm.h" 16 #include "mbuf.h" 17 #include "socket.h" 18 #include "socketvar.h" 19 #include "errno.h" 20 #include "ioctl.h" 21 #include "protosw.h" 22 23 #include "../net/if.h" 24 #include "../net/netisr.h" 25 #include "../net/route.h" 26 27 #include "../netinet/in.h" 28 #include "../netinet/in_systm.h" 29 #include "../netinet/in_var.h" 30 #include "../netinet/ip.h" 31 #include "../netinet/ip_var.h" 32 33 #ifdef vax 34 #include "../vax/mtpr.h" 35 #endif 36 37 #include "../netns/ns.h" 38 #include "../netns/ns_if.h" 39 #include "../netns/idp.h" 40 41 #ifdef BBNNET 42 #include "../bbnnet/in_pcb.h" 43 #include "../bbnnet/nopcb.h" 44 #endif 45 46 struct ifnet_en { 47 struct ifnet ifen_ifnet; 48 struct route ifen_route; 49 struct in_addr ifen_src; 50 struct in_addr ifen_dst; 51 }; 52 53 int nsipoutput(), nsipioctl(); 54 #define LOMTU (1024+512); 55 56 struct ifnet nsipif; 57 union ns_net nsip_net; 58 struct mbuf *nsip_list; /* list of all hosts and gateways or 59 broadcast addrs */ 60 61 struct mbuf * 62 nsipattach() 63 { 64 register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 65 register struct ifnet *ifp; 66 67 if (m == NULL) return (NULL); 68 m->m_off = MMINOFF; 69 m->m_len = sizeof(struct ifnet_en); 70 m->m_next = nsip_list; 71 nsip_list = m; 72 ifp = mtod(m, struct ifnet *); 73 74 ifp->if_name = "nsip"; 75 ifp->if_mtu = LOMTU; 76 ifp->if_ioctl = nsipioctl; 77 ifp->if_output = nsipoutput; 78 ifp->if_flags = IFF_POINTOPOINT; 79 ifp->if_unit = nsipif.if_unit++; 80 if_attach(ifp); 81 return (dtom(ifp)); 82 } 83 84 85 /* 86 * Process an ioctl request. 87 */ 88 /* ARGSUSED */ 89 nsipioctl(ifp, cmd, data) 90 register struct ifnet *ifp; 91 int cmd; 92 caddr_t data; 93 { 94 int error = 0; 95 struct ifreq *ifr; 96 97 switch (cmd) { 98 99 case SIOCSIFADDR: 100 ifp->if_flags |= IFF_UP; 101 /* fall into: */ 102 103 case SIOCSIFDSTADDR: 104 /* 105 * Everything else is done at a higher level. 106 */ 107 break; 108 109 case SIOCSIFFLAGS: 110 ifr = (struct ifreq *)data; 111 if ((ifr->ifr_flags & IFF_UP) == 0) 112 error = nsip_free(ifp); 113 114 115 default: 116 error = EINVAL; 117 } 118 return (error); 119 } 120 121 struct mbuf *nsip_badlen; 122 struct mbuf *nsip_lastin; 123 int nsip_hold_input; 124 125 idpip_input(m, ifp) 126 register struct mbuf *m; 127 struct ifnet *ifp; 128 { 129 register struct ip *ip; 130 register struct idp *idp; 131 register struct ifqueue *ifq = &nsintrq; 132 int len, s; 133 134 if (nsip_hold_input) { 135 if (nsip_lastin) { 136 m_freem(nsip_lastin); 137 } 138 nsip_lastin = m_copy(m, 0, (int)M_COPYALL); 139 } 140 /* 141 * Get IP and IDP header together in first mbuf. 142 */ 143 nsipif.if_ipackets++; 144 s = sizeof (struct ip) + sizeof (struct idp); 145 if ((m->m_off > MMAXOFF || m->m_len < s) && 146 (m = m_pullup(m, s)) == 0) { 147 nsipif.if_ierrors++; 148 return; 149 } 150 ip = mtod(m, struct ip *); 151 #ifndef BBNNET 152 if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 153 ip_stripoptions(ip, (struct mbuf *)0); 154 if (m->m_len < s) { 155 if ((m = m_pullup(m, s)) == 0) { 156 nsipif.if_ierrors++; 157 return; 158 } 159 ip = mtod(m, struct ip *); 160 } 161 } 162 #endif 163 164 /* 165 * Make mbuf data length reflect IDP length. 166 * If not enough data to reflect IDP length, drop. 167 */ 168 m->m_off += sizeof (struct ip); 169 m->m_len -= sizeof (struct ip); 170 idp = mtod(m, struct idp *); 171 len = ntohs(idp->idp_len); 172 if (len & 1) len++; /* Preserve Garbage Byte */ 173 if (ip->ip_len != len) { 174 if (len > ip->ip_len) { 175 nsipif.if_ierrors++; 176 if (nsip_badlen) m_freem(nsip_badlen); 177 nsip_badlen = m; 178 return; 179 } 180 /* Any extra will be trimmed off by the NS routines */ 181 } 182 183 /* 184 * Place interface pointer before the data 185 * for the receiving protocol. 186 */ 187 if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 188 m->m_off -= sizeof(struct ifnet *); 189 m->m_len += sizeof(struct ifnet *); 190 } else { 191 struct mbuf *n; 192 193 n = m_get(M_DONTWAIT, MT_HEADER); 194 if (n == (struct mbuf *)0) 195 goto bad; 196 n->m_off = MMINOFF; 197 n->m_len = sizeof(struct ifnet *); 198 n->m_next = m; 199 m = n; 200 } 201 *(mtod(m, struct ifnet **)) = ifp; 202 203 /* 204 * Deliver to NS 205 */ 206 s = splimp(); 207 if (IF_QFULL(ifq)) { 208 IF_DROP(ifq); 209 bad: 210 m_freem(m); 211 splx(s); 212 return; 213 } 214 IF_ENQUEUE(ifq, m); 215 schednetisr(NETISR_NS); 216 splx(s); 217 return; 218 } 219 220 /* ARGSUSED */ 221 nsipoutput(ifn, m0, dst) 222 struct ifnet_en *ifn; 223 struct mbuf *m0; 224 struct sockaddr *dst; 225 { 226 227 register struct mbuf *m = dtom(ifn); 228 register struct ip *ip; 229 register struct route *ro = &(ifn->ifen_route); 230 register int len = 0; 231 register struct idp *idp = mtod(m0, struct idp *); 232 int error; 233 234 if (m->m_len != sizeof(struct ifnet_en)) { 235 printf("nsipoutput: bad dst ifp %x\n", ifn); 236 goto bad; 237 } 238 ifn->ifen_ifnet.if_opackets++; 239 nsipif.if_opackets++; 240 241 242 /* 243 * Calculate data length and make space 244 * for IP header. 245 */ 246 len = ntohs(idp->idp_len); 247 if (len & 1) len++; /* Preserve Garbage Byte */ 248 m = m0; 249 if (m->m_off < MMINOFF + sizeof (struct ip)) { 250 m = m_get(M_DONTWAIT, MT_HEADER); 251 if (m == 0) { 252 m_freem(m0); 253 return (ENOBUFS); 254 } 255 m->m_off = MMAXOFF - sizeof (struct ip); 256 m->m_len = sizeof (struct ip); 257 m->m_next = m0; 258 } else { 259 m->m_off -= sizeof (struct ip); 260 m->m_len += sizeof (struct ip); 261 } 262 /* 263 * Fill in IP header. 264 */ 265 ip = mtod(m, struct ip *); 266 *(long *)ip = 0; 267 ip->ip_p = IPPROTO_IDP; 268 ip->ip_src = ifn->ifen_src; 269 ip->ip_dst = ifn->ifen_dst; 270 #ifdef BBNNET 271 ip->ip_tos = 0; 272 NOPCB_IPSEND(m, len, 0, error); 273 #else 274 ip->ip_len = (u_short)len + sizeof (struct ip); 275 ip->ip_ttl = MAXTTL; 276 277 /* 278 * Output final datagram. 279 */ 280 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 281 #endif 282 if (error) { 283 ifn->ifen_ifnet.if_oerrors++; 284 ifn->ifen_ifnet.if_ierrors = error; 285 } 286 return (error); 287 bad: 288 m_freem(m0); 289 return (ENETUNREACH); 290 } 291 292 struct ifreq ifr = {"nsip0"}; 293 294 nsip_route(m) 295 register struct mbuf *m; 296 { 297 register struct nsip_req *rq = mtod(m, struct nsip_req *); 298 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 299 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 300 struct route ro; 301 struct ifnet_en *ifn; 302 struct sockaddr_in *src; 303 304 /* 305 * First, make sure we already have an ns address: 306 */ 307 if (ns_hosteqnh(ns_thishost, ns_zerohost)) 308 return (EADDRNOTAVAIL); 309 /* 310 * Now, determine if we can get to the destination 311 */ 312 bzero((caddr_t)&ro, sizeof (ro)); 313 ro.ro_dst = *(struct sockaddr *)ip_dst; 314 rtalloc(&ro); 315 if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 316 return (ENETUNREACH); 317 } 318 319 /* 320 * And see how he's going to get back to us: 321 * i.e., what return ip address do we use? 322 */ 323 { 324 register struct in_ifaddr *ia; 325 struct ifnet *ifp = ro.ro_rt->rt_ifp; 326 327 for (ia = in_ifaddr; ia; ia = ia->ia_next) 328 if (ia->ia_ifp == ifp) 329 break; 330 if (ia == 0) 331 ia = in_ifaddr; 332 if (ia == 0) { 333 RTFREE(ro.ro_rt); 334 return (EADDRNOTAVAIL); 335 } 336 src = (struct sockaddr_in *)&ia->ia_addr; 337 } 338 339 /* 340 * Is there a free (pseudo-)interface or space? 341 */ 342 for (m = nsip_list; m; m = m->m_next) { 343 struct ifnet *ifp = mtod(m, struct ifnet *); 344 if ((ifp->if_flags & IFF_UP) == 0) 345 break; 346 } 347 if (m == (struct mbuf *) 0) 348 m = nsipattach(); 349 if (m == NULL) { 350 RTFREE(ro.ro_rt); 351 return (ENOBUFS); 352 } 353 ifn = mtod(m, struct ifnet_en *); 354 355 ifn->ifen_route = ro; 356 ifn->ifen_dst = ip_dst->sin_addr; 357 ifn->ifen_src = src->sin_addr; 358 359 /* 360 * now configure this as a point to point link 361 */ 362 ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 363 ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 364 (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr, 365 (struct ifnet *)ifn); 366 satons_addr(ifr.ifr_addr).x_host = ns_thishost; 367 return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 368 (struct ifnet *)ifn)); 369 } 370 371 nsip_free(ifp) 372 struct ifnet *ifp; 373 { 374 register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 375 struct route *ro = & ifn->ifen_route; 376 377 if (ro->ro_rt) { 378 RTFREE(ro->ro_rt); 379 ro->ro_rt = 0; 380 } 381 ifp->if_flags &= ~IFF_UP; 382 return (0); 383 } 384 385 nsip_ctlinput(cmd, sa) 386 int cmd; 387 struct sockaddr *sa; 388 { 389 extern u_char inetctlerrmap[]; 390 struct sockaddr_in *sin; 391 int in_rtchange(); 392 393 if ((unsigned)cmd >= PRC_NCMDS) 394 return; 395 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 396 return; 397 sin = (struct sockaddr_in *)sa; 398 if (sin->sin_addr.s_addr == INADDR_ANY) 399 return; 400 401 switch (cmd) { 402 403 case PRC_ROUTEDEAD: 404 case PRC_REDIRECT_NET: 405 case PRC_REDIRECT_HOST: 406 case PRC_REDIRECT_TOSNET: 407 case PRC_REDIRECT_TOSHOST: 408 nsip_rtchange(&sin->sin_addr); 409 break; 410 } 411 } 412 413 nsip_rtchange(dst) 414 register struct in_addr *dst; 415 { 416 register struct mbuf *m; 417 register struct ifnet_en *ifn; 418 419 for (m = nsip_list; m; m = m->m_next) { 420 ifn = mtod(m, struct ifnet_en *); 421 if (ifn->ifen_dst.s_addr == dst->s_addr && 422 ifn->ifen_route.ro_rt) { 423 RTFREE(ifn->ifen_route.ro_rt); 424 ifn->ifen_route.ro_rt = 0; 425 } 426 } 427 } 428 #endif 429