123210Smckusick /* 233371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 333371Ssklower * All rights reserved. 423210Smckusick * 533371Ssklower * Redistribution and use in source and binary forms are permitted 6*34856Sbostic * provided that the above copyright notice and this paragraph are 7*34856Sbostic * duplicated in all such forms and that any documentation, 8*34856Sbostic * advertising materials, and other materials related to such 9*34856Sbostic * distribution and use acknowledge that the software was developed 10*34856Sbostic * by the University of California, Berkeley. The name of the 11*34856Sbostic * University may not be used to endorse or promote products derived 12*34856Sbostic * from this software without specific prior written permission. 13*34856Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34856Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34856Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633371Ssklower * 17*34856Sbostic * @(#)ns_ip.c 7.3 (Berkeley) 06/29/88 1823210Smckusick */ 1921487Ssklower 2021487Ssklower /* 2121487Ssklower * Software interface driver for encapsulating ns in ip. 2221487Ssklower */ 2321487Ssklower 2421487Ssklower #ifdef NSIP 2521487Ssklower #include "param.h" 2621487Ssklower #include "systm.h" 2721487Ssklower #include "mbuf.h" 2821487Ssklower #include "socket.h" 2924226Ssklower #include "socketvar.h" 3021487Ssklower #include "errno.h" 3121487Ssklower #include "ioctl.h" 3225055Ssklower #include "protosw.h" 3321487Ssklower 3421487Ssklower #include "../net/if.h" 3521487Ssklower #include "../net/netisr.h" 3621487Ssklower #include "../net/route.h" 3721487Ssklower 3821487Ssklower #include "../netinet/in.h" 3921487Ssklower #include "../netinet/in_systm.h" 4021487Ssklower #include "../netinet/in_var.h" 4121487Ssklower #include "../netinet/ip.h" 4221487Ssklower #include "../netinet/ip_var.h" 4321487Ssklower 4421487Ssklower #ifdef vax 4521487Ssklower #include "../vax/mtpr.h" 4621487Ssklower #endif 4721487Ssklower 4821487Ssklower #include "../netns/ns.h" 4921487Ssklower #include "../netns/ns_if.h" 5021487Ssklower #include "../netns/idp.h" 5121487Ssklower 5221487Ssklower struct ifnet_en { 5321487Ssklower struct ifnet ifen_ifnet; 5421487Ssklower struct route ifen_route; 5521487Ssklower struct in_addr ifen_src; 5621487Ssklower struct in_addr ifen_dst; 5721487Ssklower }; 5821487Ssklower 5921487Ssklower int nsipoutput(), nsipioctl(); 6021487Ssklower #define LOMTU (1024+512); 6121487Ssklower 6221487Ssklower struct ifnet nsipif; 6321487Ssklower struct mbuf *nsip_list; /* list of all hosts and gateways or 6421487Ssklower broadcast addrs */ 6521487Ssklower 6621487Ssklower struct mbuf * 6721487Ssklower nsipattach() 6821487Ssklower { 6921487Ssklower register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 7021487Ssklower register struct ifnet *ifp; 7121487Ssklower 7225454Ssklower if (m == NULL) return (NULL); 7321487Ssklower m->m_off = MMINOFF; 7421487Ssklower m->m_len = sizeof(struct ifnet_en); 7521487Ssklower m->m_next = nsip_list; 7621487Ssklower nsip_list = m; 7721487Ssklower ifp = mtod(m, struct ifnet *); 7821487Ssklower 7921487Ssklower ifp->if_name = "nsip"; 8021487Ssklower ifp->if_mtu = LOMTU; 8121487Ssklower ifp->if_ioctl = nsipioctl; 8221487Ssklower ifp->if_output = nsipoutput; 8321487Ssklower ifp->if_flags = IFF_POINTOPOINT; 8421487Ssklower ifp->if_unit = nsipif.if_unit++; 8521487Ssklower if_attach(ifp); 8625454Ssklower return (dtom(ifp)); 8721487Ssklower } 8821487Ssklower 8921487Ssklower 9021487Ssklower /* 9121487Ssklower * Process an ioctl request. 9221487Ssklower */ 9321487Ssklower /* ARGSUSED */ 9421487Ssklower nsipioctl(ifp, cmd, data) 9521487Ssklower register struct ifnet *ifp; 9621487Ssklower int cmd; 9721487Ssklower caddr_t data; 9821487Ssklower { 9921487Ssklower int error = 0; 10025055Ssklower struct ifreq *ifr; 10121487Ssklower 10221487Ssklower switch (cmd) { 10321487Ssklower 10421487Ssklower case SIOCSIFADDR: 10521487Ssklower ifp->if_flags |= IFF_UP; 10625454Ssklower /* fall into: */ 10725454Ssklower 10825454Ssklower case SIOCSIFDSTADDR: 10921487Ssklower /* 11021487Ssklower * Everything else is done at a higher level. 11121487Ssklower */ 11221487Ssklower break; 11321487Ssklower 11425055Ssklower case SIOCSIFFLAGS: 11525055Ssklower ifr = (struct ifreq *)data; 11625055Ssklower if ((ifr->ifr_flags & IFF_UP) == 0) 11725055Ssklower error = nsip_free(ifp); 11825055Ssklower 11925055Ssklower 12021487Ssklower default: 12121487Ssklower error = EINVAL; 12221487Ssklower } 12321487Ssklower return (error); 12421487Ssklower } 12521487Ssklower 12621487Ssklower struct mbuf *nsip_badlen; 12721487Ssklower struct mbuf *nsip_lastin; 12821487Ssklower int nsip_hold_input; 12921487Ssklower 13024562Skarels idpip_input(m, ifp) 13124562Skarels register struct mbuf *m; 13224562Skarels struct ifnet *ifp; 13321487Ssklower { 13421487Ssklower register struct ip *ip; 13521487Ssklower register struct idp *idp; 13621487Ssklower register struct ifqueue *ifq = &nsintrq; 13721487Ssklower int len, s; 13821487Ssklower 13925454Ssklower if (nsip_hold_input) { 14025454Ssklower if (nsip_lastin) { 14124226Ssklower m_freem(nsip_lastin); 14221487Ssklower } 14324562Skarels nsip_lastin = m_copy(m, 0, (int)M_COPYALL); 14421487Ssklower } 14521487Ssklower /* 14621487Ssklower * Get IP and IDP header together in first mbuf. 14721487Ssklower */ 14821487Ssklower nsipif.if_ipackets++; 14921487Ssklower s = sizeof (struct ip) + sizeof (struct idp); 15021487Ssklower if ((m->m_off > MMAXOFF || m->m_len < s) && 15125454Ssklower (m = m_pullup(m, s)) == 0) { 15221487Ssklower nsipif.if_ierrors++; 15321487Ssklower return; 15421487Ssklower } 15521487Ssklower ip = mtod(m, struct ip *); 15624827Skarels if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 15724827Skarels ip_stripoptions(ip, (struct mbuf *)0); 15824827Skarels if (m->m_len < s) { 15925454Ssklower if ((m = m_pullup(m, s)) == 0) { 16024827Skarels nsipif.if_ierrors++; 16124827Skarels return; 16224827Skarels } 16324827Skarels ip = mtod(m, struct ip *); 16424827Skarels } 16524827Skarels } 16621487Ssklower 16721487Ssklower /* 16821487Ssklower * Make mbuf data length reflect IDP length. 16921487Ssklower * If not enough data to reflect IDP length, drop. 17021487Ssklower */ 17121487Ssklower m->m_off += sizeof (struct ip); 17221487Ssklower m->m_len -= sizeof (struct ip); 17321487Ssklower idp = mtod(m, struct idp *); 17421487Ssklower len = ntohs(idp->idp_len); 17523839Ssklower if (len & 1) len++; /* Preserve Garbage Byte */ 17621487Ssklower if (ip->ip_len != len) { 17721487Ssklower if (len > ip->ip_len) { 17821487Ssklower nsipif.if_ierrors++; 17925454Ssklower if (nsip_badlen) m_freem(nsip_badlen); 18021487Ssklower nsip_badlen = m; 18121487Ssklower return; 18221487Ssklower } 18324043Ssklower /* Any extra will be trimmed off by the NS routines */ 18421487Ssklower } 18524562Skarels 18621487Ssklower /* 18724562Skarels * Place interface pointer before the data 18824562Skarels * for the receiving protocol. 18924562Skarels */ 19024562Skarels if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 19124562Skarels m->m_off -= sizeof(struct ifnet *); 19224562Skarels m->m_len += sizeof(struct ifnet *); 19324562Skarels } else { 19424562Skarels struct mbuf *n; 19524562Skarels 19624562Skarels n = m_get(M_DONTWAIT, MT_HEADER); 19724562Skarels if (n == (struct mbuf *)0) 19824562Skarels goto bad; 19924562Skarels n->m_off = MMINOFF; 20024562Skarels n->m_len = sizeof(struct ifnet *); 20124562Skarels n->m_next = m; 20224562Skarels m = n; 20324562Skarels } 20424562Skarels *(mtod(m, struct ifnet **)) = ifp; 20524562Skarels 20624562Skarels /* 20721487Ssklower * Deliver to NS 20821487Ssklower */ 20921487Ssklower s = splimp(); 21021487Ssklower if (IF_QFULL(ifq)) { 21121487Ssklower IF_DROP(ifq); 21224562Skarels bad: 21324562Skarels m_freem(m); 21421487Ssklower splx(s); 21524226Ssklower return; 21621487Ssklower } 21724562Skarels IF_ENQUEUE(ifq, m); 21821487Ssklower schednetisr(NETISR_NS); 21921487Ssklower splx(s); 22024226Ssklower return; 22121487Ssklower } 22221487Ssklower 22324226Ssklower /* ARGSUSED */ 22421487Ssklower nsipoutput(ifn, m0, dst) 22521487Ssklower struct ifnet_en *ifn; 22621487Ssklower struct mbuf *m0; 22721487Ssklower struct sockaddr *dst; 22821487Ssklower { 22921487Ssklower 23021487Ssklower register struct mbuf *m = dtom(ifn); 23121487Ssklower register struct ip *ip; 23221487Ssklower register struct route *ro = &(ifn->ifen_route); 23321487Ssklower register int len = 0; 23421487Ssklower register struct idp *idp = mtod(m0, struct idp *); 23521487Ssklower int error; 23621487Ssklower 23721487Ssklower if (m->m_len != sizeof(struct ifnet_en)) { 23821487Ssklower printf("nsipoutput: bad dst ifp %x\n", ifn); 23921487Ssklower goto bad; 24021487Ssklower } 24121487Ssklower ifn->ifen_ifnet.if_opackets++; 24221487Ssklower nsipif.if_opackets++; 24321487Ssklower 24421487Ssklower 24521487Ssklower /* 24621487Ssklower * Calculate data length and make space 24721487Ssklower * for IP header. 24821487Ssklower */ 24921487Ssklower len = ntohs(idp->idp_len); 25023839Ssklower if (len & 1) len++; /* Preserve Garbage Byte */ 25121487Ssklower m = m0; 25225454Ssklower if (m->m_off < MMINOFF + sizeof (struct ip)) { 25321487Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 25421487Ssklower if (m == 0) { 25521487Ssklower m_freem(m0); 25621487Ssklower return (ENOBUFS); 25721487Ssklower } 25821487Ssklower m->m_off = MMAXOFF - sizeof (struct ip); 25921487Ssklower m->m_len = sizeof (struct ip); 26021487Ssklower m->m_next = m0; 26121487Ssklower } else { 26221487Ssklower m->m_off -= sizeof (struct ip); 26321487Ssklower m->m_len += sizeof (struct ip); 26421487Ssklower } 26521487Ssklower /* 26621487Ssklower * Fill in IP header. 26721487Ssklower */ 26821487Ssklower ip = mtod(m, struct ip *); 26921487Ssklower *(long *)ip = 0; 27024043Ssklower ip->ip_p = IPPROTO_IDP; 27121487Ssklower ip->ip_src = ifn->ifen_src; 27221487Ssklower ip->ip_dst = ifn->ifen_dst; 27321487Ssklower ip->ip_len = (u_short)len + sizeof (struct ip); 27421487Ssklower ip->ip_ttl = MAXTTL; 27521487Ssklower 27621487Ssklower /* 27721487Ssklower * Output final datagram. 27821487Ssklower */ 27921487Ssklower error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 28021487Ssklower if (error) { 28121487Ssklower ifn->ifen_ifnet.if_oerrors++; 28221487Ssklower ifn->ifen_ifnet.if_ierrors = error; 28321487Ssklower } 28421487Ssklower return (error); 28521487Ssklower bad: 28621487Ssklower m_freem(m0); 28725454Ssklower return (ENETUNREACH); 28821487Ssklower } 28921487Ssklower 29021487Ssklower struct ifreq ifr = {"nsip0"}; 29121487Ssklower 29221487Ssklower nsip_route(m) 29321487Ssklower register struct mbuf *m; 29421487Ssklower { 29521487Ssklower register struct nsip_req *rq = mtod(m, struct nsip_req *); 29621487Ssklower struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 29721487Ssklower struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 29821487Ssklower struct route ro; 29921487Ssklower struct ifnet_en *ifn; 30021487Ssklower struct sockaddr_in *src; 30125454Ssklower 30221487Ssklower /* 30325454Ssklower * First, make sure we already have an ns address: 30421487Ssklower */ 30525454Ssklower if (ns_hosteqnh(ns_thishost, ns_zerohost)) 30625454Ssklower return (EADDRNOTAVAIL); 30725454Ssklower /* 30825454Ssklower * Now, determine if we can get to the destination 30925454Ssklower */ 31021487Ssklower bzero((caddr_t)&ro, sizeof (ro)); 31121487Ssklower ro.ro_dst = *(struct sockaddr *)ip_dst; 31221487Ssklower rtalloc(&ro); 31324226Ssklower if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 31421487Ssklower return (ENETUNREACH); 31521487Ssklower } 31625454Ssklower 31721487Ssklower /* 31821487Ssklower * And see how he's going to get back to us: 31925454Ssklower * i.e., what return ip address do we use? 32021487Ssklower */ 32121487Ssklower { 32221487Ssklower register struct in_ifaddr *ia; 32321487Ssklower struct ifnet *ifp = ro.ro_rt->rt_ifp; 32421487Ssklower 32521487Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 32621487Ssklower if (ia->ia_ifp == ifp) 32721487Ssklower break; 32821487Ssklower if (ia == 0) 32921487Ssklower ia = in_ifaddr; 33021487Ssklower if (ia == 0) { 33125454Ssklower RTFREE(ro.ro_rt); 33221487Ssklower return (EADDRNOTAVAIL); 33321487Ssklower } 33421487Ssklower src = (struct sockaddr_in *)&ia->ia_addr; 33521487Ssklower } 33625454Ssklower 33721487Ssklower /* 33825055Ssklower * Is there a free (pseudo-)interface or space? 33921487Ssklower */ 34025055Ssklower for (m = nsip_list; m; m = m->m_next) { 34125055Ssklower struct ifnet *ifp = mtod(m, struct ifnet *); 34225055Ssklower if ((ifp->if_flags & IFF_UP) == 0) 34325055Ssklower break; 34425055Ssklower } 34525055Ssklower if (m == (struct mbuf *) 0) 34625055Ssklower m = nsipattach(); 34725454Ssklower if (m == NULL) { 34825454Ssklower RTFREE(ro.ro_rt); 34925454Ssklower return (ENOBUFS); 35025454Ssklower } 35121487Ssklower ifn = mtod(m, struct ifnet_en *); 35221487Ssklower 35321487Ssklower ifn->ifen_route = ro; 35421487Ssklower ifn->ifen_dst = ip_dst->sin_addr; 35521487Ssklower ifn->ifen_src = src->sin_addr; 35621487Ssklower 35721487Ssklower /* 35821487Ssklower * now configure this as a point to point link 35921487Ssklower */ 36021487Ssklower ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 36121487Ssklower ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 36225454Ssklower (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr, 36325454Ssklower (struct ifnet *)ifn); 36425454Ssklower satons_addr(ifr.ifr_addr).x_host = ns_thishost; 36525454Ssklower return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 36621487Ssklower (struct ifnet *)ifn)); 36721487Ssklower } 36825055Ssklower 36925055Ssklower nsip_free(ifp) 37025055Ssklower struct ifnet *ifp; 37125055Ssklower { 37225055Ssklower register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 37325055Ssklower struct route *ro = & ifn->ifen_route; 37425055Ssklower 37525055Ssklower if (ro->ro_rt) { 37625055Ssklower RTFREE(ro->ro_rt); 37725055Ssklower ro->ro_rt = 0; 37825055Ssklower } 37925055Ssklower ifp->if_flags &= ~IFF_UP; 38025055Ssklower return (0); 38125055Ssklower } 38225055Ssklower 38325055Ssklower nsip_ctlinput(cmd, sa) 38425055Ssklower int cmd; 38525055Ssklower struct sockaddr *sa; 38625055Ssklower { 38725055Ssklower extern u_char inetctlerrmap[]; 38825055Ssklower struct sockaddr_in *sin; 38925055Ssklower int in_rtchange(); 39025055Ssklower 39125454Ssklower if ((unsigned)cmd >= PRC_NCMDS) 39225055Ssklower return; 39325055Ssklower if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 39425055Ssklower return; 39525055Ssklower sin = (struct sockaddr_in *)sa; 39625055Ssklower if (sin->sin_addr.s_addr == INADDR_ANY) 39725055Ssklower return; 39825055Ssklower 39925055Ssklower switch (cmd) { 40025055Ssklower 40125055Ssklower case PRC_ROUTEDEAD: 40225055Ssklower case PRC_REDIRECT_NET: 40325055Ssklower case PRC_REDIRECT_HOST: 40425055Ssklower case PRC_REDIRECT_TOSNET: 40525055Ssklower case PRC_REDIRECT_TOSHOST: 40625055Ssklower nsip_rtchange(&sin->sin_addr); 40725055Ssklower break; 40825055Ssklower } 40925055Ssklower } 41025055Ssklower 41125055Ssklower nsip_rtchange(dst) 41225055Ssklower register struct in_addr *dst; 41325055Ssklower { 41425055Ssklower register struct mbuf *m; 41525055Ssklower register struct ifnet_en *ifn; 41625055Ssklower 41725211Smckusick for (m = nsip_list; m; m = m->m_next) { 41825211Smckusick ifn = mtod(m, struct ifnet_en *); 41925055Ssklower if (ifn->ifen_dst.s_addr == dst->s_addr && 42025055Ssklower ifn->ifen_route.ro_rt) { 42125055Ssklower RTFREE(ifn->ifen_route.ro_rt); 42225055Ssklower ifn->ifen_route.ro_rt = 0; 42325055Ssklower } 42425211Smckusick } 42525055Ssklower } 42621487Ssklower #endif 427