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_ip.c 7.2 (Berkeley) 1/20/88 13: */ 14: 15: /* 16: * Software interface driver for encapsulating ns in ip. 17: */ 18: 19: #include "param.h" 20: #ifdef NSIP 21: #include "systm.h" 22: #include "mbuf.h" 23: #include "socket.h" 24: #include "socketvar.h" 25: #include "errno.h" 26: #include "ioctl.h" 27: #include "protosw.h" 28: 29: #include "../net/if.h" 30: #include "../net/netisr.h" 31: #include "../net/route.h" 32: 33: #include "../netinet/in.h" 34: #include "../netinet/in_systm.h" 35: #include "../netinet/in_var.h" 36: #include "../netinet/ip.h" 37: #include "../netinet/ip_var.h" 38: 39: #ifdef vax 40: #include "../vax/mtpr.h" 41: #endif 42: 43: #include "../netns/ns.h" 44: #include "../netns/ns_if.h" 45: #include "../netns/idp.h" 46: 47: struct ifnet_en { 48: struct ifnet ifen_ifnet; 49: struct route ifen_route; 50: struct in_addr ifen_src; 51: struct in_addr ifen_dst; 52: }; 53: 54: int nsipoutput(), nsipioctl(); 55: #define LOMTU (1024+512); 56: 57: struct ifnet nsipif; 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: if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 152: ip_stripoptions(ip, (struct mbuf *)0); 153: if (m->m_len < s) { 154: if ((m = m_pullup(m, s)) == 0) { 155: nsipif.if_ierrors++; 156: return; 157: } 158: ip = mtod(m, struct ip *); 159: } 160: } 161: 162: /* 163: * Make mbuf data length reflect IDP length. 164: * If not enough data to reflect IDP length, drop. 165: */ 166: m->m_off += sizeof (struct ip); 167: m->m_len -= sizeof (struct ip); 168: idp = mtod(m, struct idp *); 169: len = ntohs(idp->idp_len); 170: if (len & 1) len++; /* Preserve Garbage Byte */ 171: if (ip->ip_len != len) { 172: if (len > ip->ip_len) { 173: nsipif.if_ierrors++; 174: if (nsip_badlen) m_freem(nsip_badlen); 175: nsip_badlen = m; 176: return; 177: } 178: /* Any extra will be trimmed off by the NS routines */ 179: } 180: 181: /* 182: * Place interface pointer before the data 183: * for the receiving protocol. 184: */ 185: if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 186: m->m_off -= sizeof(struct ifnet *); 187: m->m_len += sizeof(struct ifnet *); 188: } else { 189: struct mbuf *n; 190: 191: n = m_get(M_DONTWAIT, MT_HEADER); 192: if (n == (struct mbuf *)0) 193: goto bad; 194: n->m_off = MMINOFF; 195: n->m_len = sizeof(struct ifnet *); 196: n->m_next = m; 197: m = n; 198: } 199: *(mtod(m, struct ifnet **)) = ifp; 200: 201: /* 202: * Deliver to NS 203: */ 204: s = splimp(); 205: if (IF_QFULL(ifq)) { 206: IF_DROP(ifq); 207: bad: 208: m_freem(m); 209: splx(s); 210: return; 211: } 212: IF_ENQUEUE(ifq, m); 213: schednetisr(NETISR_NS); 214: splx(s); 215: return; 216: } 217: 218: /* ARGSUSED */ 219: nsipoutput(ifn, m0, dst) 220: struct ifnet_en *ifn; 221: struct mbuf *m0; 222: struct sockaddr *dst; 223: { 224: 225: register struct mbuf *m = dtom(ifn); 226: register struct ip *ip; 227: register struct route *ro = &(ifn->ifen_route); 228: register int len = 0; 229: register struct idp *idp = mtod(m0, struct idp *); 230: int error; 231: 232: if (m->m_len != sizeof(struct ifnet_en)) { 233: printf("nsipoutput: bad dst ifp %x\n", ifn); 234: goto bad; 235: } 236: ifn->ifen_ifnet.if_opackets++; 237: nsipif.if_opackets++; 238: 239: 240: /* 241: * Calculate data length and make space 242: * for IP header. 243: */ 244: len = ntohs(idp->idp_len); 245: if (len & 1) len++; /* Preserve Garbage Byte */ 246: m = m0; 247: if (m->m_off < MMINOFF + sizeof (struct ip)) { 248: m = m_get(M_DONTWAIT, MT_HEADER); 249: if (m == 0) { 250: m_freem(m0); 251: return (ENOBUFS); 252: } 253: m->m_off = MMAXOFF - sizeof (struct ip); 254: m->m_len = sizeof (struct ip); 255: m->m_next = m0; 256: } else { 257: m->m_off -= sizeof (struct ip); 258: m->m_len += sizeof (struct ip); 259: } 260: /* 261: * Fill in IP header. 262: */ 263: ip = mtod(m, struct ip *); 264: *(long *)ip = 0; 265: ip->ip_p = IPPROTO_IDP; 266: ip->ip_src = ifn->ifen_src; 267: ip->ip_dst = ifn->ifen_dst; 268: ip->ip_len = (u_short)len + sizeof (struct ip); 269: ip->ip_ttl = MAXTTL; 270: 271: /* 272: * Output final datagram. 273: */ 274: error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 275: if (error) { 276: ifn->ifen_ifnet.if_oerrors++; 277: ifn->ifen_ifnet.if_ierrors = error; 278: } 279: return (error); 280: bad: 281: m_freem(m0); 282: return (ENETUNREACH); 283: } 284: 285: struct ifreq ifr = {"nsip0"}; 286: 287: nsip_route(m) 288: register struct mbuf *m; 289: { 290: register struct nsip_req *rq = mtod(m, struct nsip_req *); 291: struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 292: struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 293: struct route ro; 294: struct ifnet_en *ifn; 295: struct sockaddr_in *src; 296: 297: /* 298: * First, make sure we already have an ns address: 299: */ 300: if (ns_hosteqnh(ns_thishost, ns_zerohost)) 301: return (EADDRNOTAVAIL); 302: /* 303: * Now, determine if we can get to the destination 304: */ 305: bzero((caddr_t)&ro, sizeof (ro)); 306: ro.ro_dst = *(struct sockaddr *)ip_dst; 307: rtalloc(&ro); 308: if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 309: return (ENETUNREACH); 310: } 311: 312: /* 313: * And see how he's going to get back to us: 314: * i.e., what return ip address do we use? 315: */ 316: { 317: register struct in_ifaddr *ia; 318: struct ifnet *ifp = ro.ro_rt->rt_ifp; 319: 320: for (ia = in_ifaddr; ia; ia = ia->ia_next) 321: if (ia->ia_ifp == ifp) 322: break; 323: if (ia == 0) 324: ia = in_ifaddr; 325: if (ia == 0) { 326: RTFREE(ro.ro_rt); 327: return (EADDRNOTAVAIL); 328: } 329: src = (struct sockaddr_in *)&ia->ia_addr; 330: } 331: 332: /* 333: * Is there a free (pseudo-)interface or space? 334: */ 335: for (m = nsip_list; m; m = m->m_next) { 336: struct ifnet *ifp = mtod(m, struct ifnet *); 337: if ((ifp->if_flags & IFF_UP) == 0) 338: break; 339: } 340: if (m == (struct mbuf *) 0) 341: m = nsipattach(); 342: if (m == NULL) { 343: RTFREE(ro.ro_rt); 344: return (ENOBUFS); 345: } 346: ifn = mtod(m, struct ifnet_en *); 347: 348: ifn->ifen_route = ro; 349: ifn->ifen_dst = ip_dst->sin_addr; 350: ifn->ifen_src = src->sin_addr; 351: 352: /* 353: * now configure this as a point to point link 354: */ 355: ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 356: ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 357: (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr, 358: (struct ifnet *)ifn); 359: satons_addr(ifr.ifr_addr).x_host = ns_thishost; 360: return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 361: (struct ifnet *)ifn)); 362: } 363: 364: nsip_free(ifp) 365: struct ifnet *ifp; 366: { 367: register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 368: struct route *ro = & ifn->ifen_route; 369: 370: if (ro->ro_rt) { 371: RTFREE(ro->ro_rt); 372: ro->ro_rt = 0; 373: } 374: ifp->if_flags &= ~IFF_UP; 375: return (0); 376: } 377: 378: nsip_ctlinput(cmd, sa) 379: int cmd; 380: struct sockaddr *sa; 381: { 382: extern u_char inetctlerrmap[]; 383: struct sockaddr_in *sin; 384: int in_rtchange(); 385: 386: if ((unsigned)cmd >= PRC_NCMDS) 387: return; 388: if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 389: return; 390: sin = (struct sockaddr_in *)sa; 391: if (sin->sin_addr.s_addr == INADDR_ANY) 392: return; 393: 394: switch (cmd) { 395: 396: case PRC_ROUTEDEAD: 397: case PRC_REDIRECT_NET: 398: case PRC_REDIRECT_HOST: 399: case PRC_REDIRECT_TOSNET: 400: case PRC_REDIRECT_TOSHOST: 401: nsip_rtchange(&sin->sin_addr); 402: break; 403: } 404: } 405: 406: nsip_rtchange(dst) 407: register struct in_addr *dst; 408: { 409: register struct mbuf *m; 410: register struct ifnet_en *ifn; 411: 412: for (m = nsip_list; m; m = m->m_next) { 413: ifn = mtod(m, struct ifnet_en *); 414: if (ifn->ifen_dst.s_addr == dst->s_addr && 415: ifn->ifen_route.ro_rt) { 416: RTFREE(ifn->ifen_route.ro_rt); 417: ifn->ifen_route.ro_rt = 0; 418: } 419: } 420: } 421: #endif