123174Smckusick /* 229071Skarels * Copyright (c) 1982, 1986 Regents of the University of California. 333183Sbostic * All rights reserved. 423174Smckusick * 533183Sbostic * Redistribution and use in source and binary forms are permitted 6*34844Sbostic * provided that the above copyright notice and this paragraph are 7*34844Sbostic * duplicated in all such forms and that any documentation, 8*34844Sbostic * advertising materials, and other materials related to such 9*34844Sbostic * distribution and use acknowledge that the software was developed 10*34844Sbostic * by the University of California, Berkeley. The name of the 11*34844Sbostic * University may not be used to endorse or promote products derived 12*34844Sbostic * from this software without specific prior written permission. 13*34844Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34844Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34844Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633183Sbostic * 17*34844Sbostic * @(#)if_loop.c 7.4 (Berkeley) 06/27/88 1823174Smckusick */ 195122Swnj 205122Swnj /* 215122Swnj * Loopback interface driver for protocol testing and timing. 225122Swnj */ 235122Swnj 2417058Sbloom #include "param.h" 2517058Sbloom #include "systm.h" 2617058Sbloom #include "mbuf.h" 2717058Sbloom #include "socket.h" 2817058Sbloom #include "errno.h" 2917058Sbloom #include "ioctl.h" 3010907Ssam 3110907Ssam #include "../net/if.h" 3210907Ssam #include "../net/netisr.h" 3310907Ssam #include "../net/route.h" 3410907Ssam 3529922Skarels #include "../machine/mtpr.h" 3629922Skarels 3724771Skarels #ifdef INET 3824771Skarels #include "../netinet/in.h" 3924771Skarels #include "../netinet/in_systm.h" 4029071Skarels #include "../netinet/in_var.h" 4124771Skarels #include "../netinet/ip.h" 4224771Skarels #endif 435122Swnj 4418815Ssklower #ifdef NS 4518815Ssklower #include "../netns/ns.h" 4618815Ssklower #include "../netns/ns_if.h" 4718815Ssklower #endif 4818815Ssklower 495207Swnj #define LOMTU (1024+512) 505122Swnj 515122Swnj struct ifnet loif; 5213066Ssam int looutput(), loioctl(); 535122Swnj 545122Swnj loattach() 555122Swnj { 565122Swnj register struct ifnet *ifp = &loif; 575122Swnj 585172Swnj ifp->if_name = "lo"; 595122Swnj ifp->if_mtu = LOMTU; 6026091Skarels ifp->if_flags = IFF_LOOPBACK; 6113066Ssam ifp->if_ioctl = loioctl; 625122Swnj ifp->if_output = looutput; 635161Swnj if_attach(ifp); 645122Swnj } 655122Swnj 666337Ssam looutput(ifp, m0, dst) 675122Swnj struct ifnet *ifp; 6824771Skarels register struct mbuf *m0; 696337Ssam struct sockaddr *dst; 705122Swnj { 7124771Skarels int s; 726209Swnj register struct ifqueue *ifq; 7324771Skarels struct mbuf *m; 745122Swnj 7524771Skarels /* 7624771Skarels * Place interface pointer before the data 7724771Skarels * for the receiving protocol. 7824771Skarels */ 7924771Skarels if (m0->m_off <= MMAXOFF && 8024771Skarels m0->m_off >= MMINOFF + sizeof(struct ifnet *)) { 8124771Skarels m0->m_off -= sizeof(struct ifnet *); 8224771Skarels m0->m_len += sizeof(struct ifnet *); 8324771Skarels } else { 8424771Skarels MGET(m, M_DONTWAIT, MT_HEADER); 8524771Skarels if (m == (struct mbuf *)0) 8624771Skarels return (ENOBUFS); 8724771Skarels m->m_off = MMINOFF; 8824771Skarels m->m_len = sizeof(struct ifnet *); 8924771Skarels m->m_next = m0; 9024771Skarels m0 = m; 9124771Skarels } 9224771Skarels *(mtod(m0, struct ifnet **)) = ifp; 9324771Skarels s = splimp(); 945172Swnj ifp->if_opackets++; 956337Ssam switch (dst->sa_family) { 965122Swnj 975122Swnj #ifdef INET 986337Ssam case AF_INET: 996209Swnj ifq = &ipintrq; 1006209Swnj if (IF_QFULL(ifq)) { 1016209Swnj IF_DROP(ifq); 1026337Ssam m_freem(m0); 1036209Swnj splx(s); 1046544Sfeldman return (ENOBUFS); 1056209Swnj } 1066209Swnj IF_ENQUEUE(ifq, m0); 1076262Swnj schednetisr(NETISR_IP); 1085122Swnj break; 1095122Swnj #endif 11018815Ssklower #ifdef NS 11118815Ssklower case AF_NS: 11218815Ssklower ifq = &nsintrq; 11318815Ssklower if (IF_QFULL(ifq)) { 11418815Ssklower IF_DROP(ifq); 11518815Ssklower m_freem(m0); 11618815Ssklower splx(s); 11718815Ssklower return (ENOBUFS); 11818815Ssklower } 11918815Ssklower IF_ENQUEUE(ifq, m0); 12018815Ssklower schednetisr(NETISR_NS); 12118815Ssklower break; 12218815Ssklower #endif 1235122Swnj default: 1245122Swnj splx(s); 1256337Ssam printf("lo%d: can't handle af%d\n", ifp->if_unit, 1266337Ssam dst->sa_family); 1276337Ssam m_freem(m0); 1286544Sfeldman return (EAFNOSUPPORT); 1295122Swnj } 1305172Swnj ifp->if_ipackets++; 1315122Swnj splx(s); 1326544Sfeldman return (0); 1335122Swnj } 13413066Ssam 13513066Ssam /* 13613066Ssam * Process an ioctl request. 13713066Ssam */ 13818370Skarels /* ARGSUSED */ 13913066Ssam loioctl(ifp, cmd, data) 14013066Ssam register struct ifnet *ifp; 14113066Ssam int cmd; 14213066Ssam caddr_t data; 14313066Ssam { 14418370Skarels int error = 0; 14513066Ssam 14613066Ssam switch (cmd) { 14713066Ssam 14813066Ssam case SIOCSIFADDR: 14918370Skarels ifp->if_flags |= IFF_UP; 15018370Skarels /* 15118370Skarels * Everything else is done at a higher level. 15218370Skarels */ 15313066Ssam break; 15413066Ssam 15513066Ssam default: 15613066Ssam error = EINVAL; 15713066Ssam } 15813066Ssam return (error); 15913066Ssam } 160