123210Smckusick /* 2*25055Ssklower * Copyright (c) 1985 Regents of the University of California. 323210Smckusick * All rights reserved. The Berkeley software License Agreement 423210Smckusick * specifies the terms and conditions for redistribution. 523210Smckusick * 6*25055Ssklower * @(#)ns_ip.c 6.9 (Berkeley) 10/01/85 723210Smckusick */ 821487Ssklower 921487Ssklower /* 1021487Ssklower * Software interface driver for encapsulating ns in ip. 1121487Ssklower */ 1221487Ssklower 1321487Ssklower #ifdef NSIP 1421487Ssklower #include "param.h" 1521487Ssklower #include "systm.h" 1621487Ssklower #include "mbuf.h" 1721487Ssklower #include "socket.h" 1824226Ssklower #include "socketvar.h" 1921487Ssklower #include "errno.h" 2021487Ssklower #include "ioctl.h" 21*25055Ssklower #include "protosw.h" 2221487Ssklower 2321487Ssklower #include "../net/if.h" 2421487Ssklower #include "../net/netisr.h" 2521487Ssklower #include "../net/route.h" 2621487Ssklower 2721487Ssklower #include "../netinet/in.h" 2821487Ssklower #include "../netinet/in_systm.h" 2921487Ssklower #include "../netinet/in_var.h" 3021487Ssklower #include "../netinet/ip.h" 3121487Ssklower #include "../netinet/ip_var.h" 3221487Ssklower 3321487Ssklower #ifdef vax 3421487Ssklower #include "../vax/mtpr.h" 3521487Ssklower #endif 3621487Ssklower 3721487Ssklower #include "../netns/ns.h" 3821487Ssklower #include "../netns/ns_if.h" 3921487Ssklower #include "../netns/idp.h" 4021487Ssklower 4124414Swalsh #ifdef BBNNET 4224414Swalsh #include "../bbnnet/in_pcb.h" 4324414Swalsh #include "../bbnnet/nopcb.h" 4424414Swalsh #endif 4524414Swalsh 4621487Ssklower struct ifnet_en { 4721487Ssklower struct ifnet ifen_ifnet; 4821487Ssklower struct route ifen_route; 4921487Ssklower struct in_addr ifen_src; 5021487Ssklower struct in_addr ifen_dst; 5121487Ssklower }; 5221487Ssklower 5321487Ssklower int nsipoutput(), nsipioctl(); 5421487Ssklower #define LOMTU (1024+512); 5521487Ssklower 5621487Ssklower struct ifnet nsipif; 5721487Ssklower union ns_net nsip_net; 5821487Ssklower struct mbuf *nsip_list; /* list of all hosts and gateways or 5921487Ssklower broadcast addrs */ 6021487Ssklower 6121487Ssklower struct mbuf * 6221487Ssklower nsipattach() 6321487Ssklower { 6421487Ssklower register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 6521487Ssklower register struct ifnet *ifp; 6621487Ssklower 6721487Ssklower if (m==0) return (0); 6821487Ssklower m->m_off = MMINOFF; 6921487Ssklower m->m_len = sizeof(struct ifnet_en); 7021487Ssklower m->m_next = nsip_list; 7121487Ssklower nsip_list = m; 7221487Ssklower ifp = mtod(m, struct ifnet *); 7321487Ssklower 7421487Ssklower ifp->if_name = "nsip"; 7521487Ssklower ifp->if_mtu = LOMTU; 7621487Ssklower ifp->if_ioctl = nsipioctl; 7721487Ssklower ifp->if_output = nsipoutput; 7821487Ssklower ifp->if_flags = IFF_POINTOPOINT; 7921487Ssklower ifp->if_unit = nsipif.if_unit++; 8021487Ssklower if_attach(ifp); 8121487Ssklower return(dtom(ifp)); 8221487Ssklower } 8321487Ssklower 8421487Ssklower 8521487Ssklower /* 8621487Ssklower * Process an ioctl request. 8721487Ssklower */ 8821487Ssklower /* ARGSUSED */ 8921487Ssklower nsipioctl(ifp, cmd, data) 9021487Ssklower register struct ifnet *ifp; 9121487Ssklower int cmd; 9221487Ssklower caddr_t data; 9321487Ssklower { 9421487Ssklower int error = 0; 95*25055Ssklower struct ifreq *ifr; 9621487Ssklower 9721487Ssklower switch (cmd) { 9821487Ssklower 9921487Ssklower case SIOCSIFADDR: 10021487Ssklower ifp->if_flags |= IFF_UP; 10121487Ssklower /* 10221487Ssklower * Everything else is done at a higher level. 10321487Ssklower */ 10421487Ssklower break; 10521487Ssklower 106*25055Ssklower case SIOCSIFFLAGS: 107*25055Ssklower ifr = (struct ifreq *)data; 108*25055Ssklower if ((ifr->ifr_flags & IFF_UP) == 0) 109*25055Ssklower error = nsip_free(ifp); 110*25055Ssklower 111*25055Ssklower 11221487Ssklower default: 11321487Ssklower error = EINVAL; 11421487Ssklower } 11521487Ssklower return (error); 11621487Ssklower } 11721487Ssklower 11821487Ssklower struct mbuf *nsip_badlen; 11921487Ssklower struct mbuf *nsip_lastin; 12021487Ssklower int nsip_hold_input; 12121487Ssklower 12224562Skarels idpip_input(m, ifp) 12324562Skarels register struct mbuf *m; 12424562Skarels struct ifnet *ifp; 12521487Ssklower { 12621487Ssklower register struct ip *ip; 12721487Ssklower register struct idp *idp; 12821487Ssklower register struct ifqueue *ifq = &nsintrq; 12921487Ssklower int len, s; 13021487Ssklower 13121487Ssklower if(nsip_hold_input) { 13221487Ssklower if(nsip_lastin) { 13324226Ssklower m_freem(nsip_lastin); 13421487Ssklower } 13524562Skarels nsip_lastin = m_copy(m, 0, (int)M_COPYALL); 13621487Ssklower } 13721487Ssklower /* 13821487Ssklower * Get IP and IDP header together in first mbuf. 13921487Ssklower */ 14021487Ssklower nsipif.if_ipackets++; 14121487Ssklower s = sizeof (struct ip) + sizeof (struct idp); 14221487Ssklower if ((m->m_off > MMAXOFF || m->m_len < s) && 14321487Ssklower (m = m_pullup(m, s))==0) { 14421487Ssklower nsipif.if_ierrors++; 14521487Ssklower return; 14621487Ssklower } 14721487Ssklower ip = mtod(m, struct ip *); 14824827Skarels if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 14924827Skarels ip_stripoptions(ip, (struct mbuf *)0); 15024827Skarels if (m->m_len < s) { 15124827Skarels if ((m = m_pullup(m, s))==0) { 15224827Skarels nsipif.if_ierrors++; 15324827Skarels return; 15424827Skarels } 15524827Skarels ip = mtod(m, struct ip *); 15624827Skarels } 15724827Skarels } 15821487Ssklower 15921487Ssklower /* 16021487Ssklower * Make mbuf data length reflect IDP length. 16121487Ssklower * If not enough data to reflect IDP length, drop. 16221487Ssklower */ 16321487Ssklower m->m_off += sizeof (struct ip); 16421487Ssklower m->m_len -= sizeof (struct ip); 16521487Ssklower idp = mtod(m, struct idp *); 16621487Ssklower len = ntohs(idp->idp_len); 16723839Ssklower if (len & 1) len++; /* Preserve Garbage Byte */ 16821487Ssklower if (ip->ip_len != len) { 16921487Ssklower if (len > ip->ip_len) { 17021487Ssklower nsipif.if_ierrors++; 17121487Ssklower if(nsip_badlen) m_freem(nsip_badlen); 17221487Ssklower nsip_badlen = m; 17321487Ssklower return; 17421487Ssklower } 17524043Ssklower /* Any extra will be trimmed off by the NS routines */ 17621487Ssklower } 17724562Skarels 17821487Ssklower /* 17924562Skarels * Place interface pointer before the data 18024562Skarels * for the receiving protocol. 18124562Skarels */ 18224562Skarels if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 18324562Skarels m->m_off -= sizeof(struct ifnet *); 18424562Skarels m->m_len += sizeof(struct ifnet *); 18524562Skarels } else { 18624562Skarels struct mbuf *n; 18724562Skarels 18824562Skarels n = m_get(M_DONTWAIT, MT_HEADER); 18924562Skarels if (n == (struct mbuf *)0) 19024562Skarels goto bad; 19124562Skarels n->m_off = MMINOFF; 19224562Skarels n->m_len = sizeof(struct ifnet *); 19324562Skarels n->m_next = m; 19424562Skarels m = n; 19524562Skarels } 19624562Skarels *(mtod(m, struct ifnet **)) = ifp; 19724562Skarels 19824562Skarels /* 19921487Ssklower * Deliver to NS 20021487Ssklower */ 20121487Ssklower s = splimp(); 20221487Ssklower if (IF_QFULL(ifq)) { 20321487Ssklower IF_DROP(ifq); 20424562Skarels bad: 20524562Skarels m_freem(m); 20621487Ssklower splx(s); 20724226Ssklower return; 20821487Ssklower } 20924562Skarels IF_ENQUEUE(ifq, m); 21021487Ssklower schednetisr(NETISR_NS); 21121487Ssklower splx(s); 21224226Ssklower return; 21321487Ssklower } 21421487Ssklower 21524226Ssklower /* ARGSUSED */ 21621487Ssklower nsipoutput(ifn, m0, dst) 21721487Ssklower struct ifnet_en *ifn; 21821487Ssklower struct mbuf *m0; 21921487Ssklower struct sockaddr *dst; 22021487Ssklower { 22121487Ssklower 22221487Ssklower register struct mbuf *m = dtom(ifn); 22321487Ssklower register struct ip *ip; 22421487Ssklower register struct route *ro = &(ifn->ifen_route); 22521487Ssklower register int len = 0; 22621487Ssklower register struct idp *idp = mtod(m0, struct idp *); 22721487Ssklower int error; 22821487Ssklower 22921487Ssklower if (m->m_len != sizeof(struct ifnet_en)) { 23021487Ssklower printf("nsipoutput: bad dst ifp %x\n", ifn); 23121487Ssklower goto bad; 23221487Ssklower } 23321487Ssklower ifn->ifen_ifnet.if_opackets++; 23421487Ssklower nsipif.if_opackets++; 23521487Ssklower 23621487Ssklower 23721487Ssklower /* 23821487Ssklower * Calculate data length and make space 23921487Ssklower * for IP header. 24021487Ssklower */ 24121487Ssklower len = ntohs(idp->idp_len); 24223839Ssklower if (len & 1) len++; /* Preserve Garbage Byte */ 24321487Ssklower m = m0; 24421487Ssklower if(m->m_off < MMINOFF + sizeof (struct ip)) { 24521487Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 24621487Ssklower if (m == 0) { 24721487Ssklower m_freem(m0); 24821487Ssklower return (ENOBUFS); 24921487Ssklower } 25021487Ssklower m->m_off = MMAXOFF - sizeof (struct ip); 25121487Ssklower m->m_len = sizeof (struct ip); 25221487Ssklower m->m_next = m0; 25321487Ssklower } else { 25421487Ssklower m->m_off -= sizeof (struct ip); 25521487Ssklower m->m_len += sizeof (struct ip); 25621487Ssklower } 25721487Ssklower /* 25821487Ssklower * Fill in IP header. 25921487Ssklower */ 26021487Ssklower ip = mtod(m, struct ip *); 26121487Ssklower *(long *)ip = 0; 26224043Ssklower ip->ip_p = IPPROTO_IDP; 26321487Ssklower ip->ip_src = ifn->ifen_src; 26421487Ssklower ip->ip_dst = ifn->ifen_dst; 26524414Swalsh #ifdef BBNNET 26624414Swalsh ip->ip_tos = 0; 26724414Swalsh NOPCB_IPSEND(m, len, 0, error); 26824414Swalsh #else 26921487Ssklower ip->ip_len = (u_short)len + sizeof (struct ip); 27021487Ssklower ip->ip_ttl = MAXTTL; 27121487Ssklower 27221487Ssklower /* 27321487Ssklower * Output final datagram. 27421487Ssklower */ 27521487Ssklower error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 27624414Swalsh #endif 27721487Ssklower if (error) { 27821487Ssklower ifn->ifen_ifnet.if_oerrors++; 27921487Ssklower ifn->ifen_ifnet.if_ierrors = error; 28021487Ssklower } 28121487Ssklower return (error); 28221487Ssklower bad: 28321487Ssklower m_freem(m0); 28421487Ssklower return(ENETUNREACH); 28521487Ssklower } 28621487Ssklower 28721487Ssklower struct ifreq ifr = {"nsip0"}; 28821487Ssklower 28921487Ssklower nsip_route(m) 29021487Ssklower register struct mbuf *m; 29121487Ssklower { 29221487Ssklower register struct nsip_req *rq = mtod(m, struct nsip_req *); 29321487Ssklower struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 29421487Ssklower struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 29521487Ssklower struct route ro; 29621487Ssklower struct ifnet_en *ifn; 29721487Ssklower struct sockaddr_in *src; 29821487Ssklower /* 29921487Ssklower * First, determine if we can get to the destination 30021487Ssklower */ 30121487Ssklower bzero((caddr_t)&ro, sizeof (ro)); 30221487Ssklower ro.ro_dst = *(struct sockaddr *)ip_dst; 30321487Ssklower rtalloc(&ro); 30424226Ssklower if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 30521487Ssklower return (ENETUNREACH); 30621487Ssklower } 30721487Ssklower /* 30821487Ssklower * And see how he's going to get back to us: 30921487Ssklower */ 31021487Ssklower { 31121487Ssklower register struct in_ifaddr *ia; 31221487Ssklower struct ifnet *ifp = ro.ro_rt->rt_ifp; 31321487Ssklower 31421487Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 31521487Ssklower if (ia->ia_ifp == ifp) 31621487Ssklower break; 31721487Ssklower if (ia == 0) 31821487Ssklower ia = in_ifaddr; 31921487Ssklower if (ia == 0) { 32021487Ssklower return (EADDRNOTAVAIL); 32121487Ssklower } 32221487Ssklower src = (struct sockaddr_in *)&ia->ia_addr; 32321487Ssklower } 32421487Ssklower /* 325*25055Ssklower * Is there a free (pseudo-)interface or space? 32621487Ssklower */ 327*25055Ssklower for (m = nsip_list; m; m = m->m_next) { 328*25055Ssklower struct ifnet *ifp = mtod(m, struct ifnet *); 329*25055Ssklower if ((ifp->if_flags & IFF_UP) == 0) 330*25055Ssklower break; 331*25055Ssklower } 332*25055Ssklower if (m == (struct mbuf *) 0) 333*25055Ssklower m = nsipattach(); 33421487Ssklower if (m==NULL) {return (ENOBUFS);} 33521487Ssklower ifn = mtod(m, struct ifnet_en *); 33621487Ssklower 33721487Ssklower ro.ro_rt->rt_use++; 33821487Ssklower ifn->ifen_route = ro; 33921487Ssklower ifn->ifen_dst = ip_dst->sin_addr; 34021487Ssklower ifn->ifen_src = src->sin_addr; 34121487Ssklower 34221487Ssklower /* 34321487Ssklower * now configure this as a point to point link 34421487Ssklower */ 34521487Ssklower ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 34621487Ssklower ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 34724226Ssklower return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 34821487Ssklower (struct ifnet *)ifn)); 34921487Ssklower } 350*25055Ssklower 351*25055Ssklower nsip_free(ifp) 352*25055Ssklower struct ifnet *ifp; 353*25055Ssklower { 354*25055Ssklower register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 355*25055Ssklower struct route *ro = & ifn->ifen_route; 356*25055Ssklower 357*25055Ssklower if (ro->ro_rt) { 358*25055Ssklower RTFREE(ro->ro_rt); 359*25055Ssklower ro->ro_rt = 0; 360*25055Ssklower } 361*25055Ssklower ifp->if_flags &= ~IFF_UP; 362*25055Ssklower return (0); 363*25055Ssklower } 364*25055Ssklower 365*25055Ssklower nsip_ctlinput(cmd, sa) 366*25055Ssklower int cmd; 367*25055Ssklower struct sockaddr *sa; 368*25055Ssklower { 369*25055Ssklower extern u_char inetctlerrmap[]; 370*25055Ssklower struct sockaddr_in *sin; 371*25055Ssklower int in_rtchange(); 372*25055Ssklower 373*25055Ssklower if ((unsigned)cmd > PRC_NCMDS) 374*25055Ssklower return; 375*25055Ssklower if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 376*25055Ssklower return; 377*25055Ssklower sin = (struct sockaddr_in *)sa; 378*25055Ssklower if (sin->sin_addr.s_addr == INADDR_ANY) 379*25055Ssklower return; 380*25055Ssklower 381*25055Ssklower switch (cmd) { 382*25055Ssklower 383*25055Ssklower case PRC_ROUTEDEAD: 384*25055Ssklower case PRC_REDIRECT_NET: 385*25055Ssklower case PRC_REDIRECT_HOST: 386*25055Ssklower case PRC_REDIRECT_TOSNET: 387*25055Ssklower case PRC_REDIRECT_TOSHOST: 388*25055Ssklower nsip_rtchange(&sin->sin_addr); 389*25055Ssklower break; 390*25055Ssklower } 391*25055Ssklower } 392*25055Ssklower 393*25055Ssklower nsip_rtchange(dst) 394*25055Ssklower register struct in_addr *dst; 395*25055Ssklower { 396*25055Ssklower register struct mbuf *m; 397*25055Ssklower register struct ifnet_en *ifn; 398*25055Ssklower 399*25055Ssklower for (m = nsip_list; m; m = m->m_next) 400*25055Ssklower if (ifn->ifen_dst.s_addr == dst->s_addr && 401*25055Ssklower ifn->ifen_route.ro_rt) { 402*25055Ssklower RTFREE(ifn->ifen_route.ro_rt); 403*25055Ssklower ifn->ifen_route.ro_rt = 0; 404*25055Ssklower } 405*25055Ssklower } 40621487Ssklower #endif 407