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