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