123174Smckusick /*
263211Sbostic * Copyright (c) 1982, 1986, 1993
363211Sbostic * The Regents of the University of California. All rights reserved.
423174Smckusick *
544464Sbostic * %sccs.include.redist.c%
633183Sbostic *
7*68168Scgd * @(#)if_loop.c 8.2 (Berkeley) 01/09/95
823174Smckusick */
95122Swnj
105122Swnj /*
115122Swnj * Loopback interface driver for protocol testing and timing.
125122Swnj */
135122Swnj
1456529Sbostic #include <sys/param.h>
1556529Sbostic #include <sys/systm.h>
1656529Sbostic #include <sys/kernel.h>
1756529Sbostic #include <sys/mbuf.h>
1856529Sbostic #include <sys/socket.h>
1956529Sbostic #include <sys/errno.h>
2056529Sbostic #include <sys/ioctl.h>
2156529Sbostic #include <sys/time.h>
2256529Sbostic #include <machine/cpu.h>
2310907Ssam
2456529Sbostic #include <net/if.h>
2556529Sbostic #include <net/if_types.h>
2656529Sbostic #include <net/netisr.h>
2756529Sbostic #include <net/route.h>
2856529Sbostic #include <net/bpf.h>
2910907Ssam
3024771Skarels #ifdef INET
3156529Sbostic #include <netinet/in.h>
3256529Sbostic #include <netinet/in_systm.h>
3356529Sbostic #include <netinet/in_var.h>
3456529Sbostic #include <netinet/ip.h>
3524771Skarels #endif
365122Swnj
3718815Ssklower #ifdef NS
3856529Sbostic #include <netns/ns.h>
3956529Sbostic #include <netns/ns_if.h>
4018815Ssklower #endif
4118815Ssklower
4237472Ssklower #ifdef ISO
4356529Sbostic #include <netiso/iso.h>
4456529Sbostic #include <netiso/iso_var.h>
4537472Ssklower #endif
4637472Ssklower
4754718Ssklower #include "bpfilter.h"
4854718Ssklower
495207Swnj #define LOMTU (1024+512)
505122Swnj
515122Swnj struct ifnet loif;
525122Swnj
5359123Storek /* ARGSUSED */
5459123Storek void
loopattach(n)5559123Storek loopattach(n)
5659123Storek int n;
575122Swnj {
585122Swnj register struct ifnet *ifp = &loif;
595122Swnj
6059123Storek #ifdef lint
6159123Storek n = n; /* Highlander: there can only be one... */
6259123Storek #endif
635172Swnj ifp->if_name = "lo";
645122Swnj ifp->if_mtu = LOMTU;
6554718Ssklower ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
6613066Ssam ifp->if_ioctl = loioctl;
675122Swnj ifp->if_output = looutput;
6837472Ssklower ifp->if_type = IFT_LOOP;
6937472Ssklower ifp->if_hdrlen = 0;
7037472Ssklower ifp->if_addrlen = 0;
715161Swnj if_attach(ifp);
7254718Ssklower #if NBPFILTER > 0
7354718Ssklower bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
7454718Ssklower #endif
755122Swnj }
765122Swnj
7761362Sbostic int
looutput(ifp,m,dst,rt)7845198Ssklower looutput(ifp, m, dst, rt)
795122Swnj struct ifnet *ifp;
8035795Skarels register struct mbuf *m;
816337Ssam struct sockaddr *dst;
8245198Ssklower register struct rtentry *rt;
835122Swnj {
8445523Ssklower int s, isr;
8545523Ssklower register struct ifqueue *ifq = 0;
865122Swnj
8735795Skarels if ((m->m_flags & M_PKTHDR) == 0)
8835795Skarels panic("looutput no HDR");
8954718Ssklower ifp->if_lastchange = time;
9054718Ssklower #if NBPFILTER > 0
9154718Ssklower if (loif.if_bpf) {
9254718Ssklower /*
9354718Ssklower * We need to prepend the address family as
9454718Ssklower * a four byte field. Cons up a dummy header
9554718Ssklower * to pacify bpf. This is safe because bpf
9654718Ssklower * will only read from the mbuf (i.e., it won't
9754718Ssklower * try to free it or keep a pointer a to it).
9854718Ssklower */
9954718Ssklower struct mbuf m0;
10054718Ssklower u_int af = dst->sa_family;
10154718Ssklower
10254718Ssklower m0.m_next = m;
10354718Ssklower m0.m_len = 4;
10454718Ssklower m0.m_data = (char *)⁡
10554718Ssklower
10654718Ssklower bpf_mtap(loif.if_bpf, &m0);
10754718Ssklower }
10854718Ssklower #endif
10935795Skarels m->m_pkthdr.rcvif = ifp;
11035795Skarels
11159009Ssklower if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
11245198Ssklower m_freem(m);
11359009Ssklower return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
11459009Ssklower rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
11545198Ssklower }
1165172Swnj ifp->if_opackets++;
11739187Ssklower ifp->if_obytes += m->m_pkthdr.len;
1186337Ssam switch (dst->sa_family) {
1195122Swnj
1205122Swnj #ifdef INET
1216337Ssam case AF_INET:
1226209Swnj ifq = &ipintrq;
12345523Ssklower isr = NETISR_IP;
1245122Swnj break;
1255122Swnj #endif
12618815Ssklower #ifdef NS
12718815Ssklower case AF_NS:
12818815Ssklower ifq = &nsintrq;
12945523Ssklower isr = NETISR_NS;
13018815Ssklower break;
13118815Ssklower #endif
13237472Ssklower #ifdef ISO
13337472Ssklower case AF_ISO:
13437472Ssklower ifq = &clnlintrq;
13545523Ssklower isr = NETISR_ISO;
13637472Ssklower break;
13737472Ssklower #endif
1385122Swnj default:
1396337Ssam printf("lo%d: can't handle af%d\n", ifp->if_unit,
1406337Ssam dst->sa_family);
14135795Skarels m_freem(m);
1426544Sfeldman return (EAFNOSUPPORT);
1435122Swnj }
14448727Ssklower s = splimp();
14545523Ssklower if (IF_QFULL(ifq)) {
14645523Ssklower IF_DROP(ifq);
14745523Ssklower m_freem(m);
14845523Ssklower splx(s);
14945523Ssklower return (ENOBUFS);
15045523Ssklower }
15145523Ssklower IF_ENQUEUE(ifq, m);
15245523Ssklower schednetisr(isr);
1535172Swnj ifp->if_ipackets++;
15439187Ssklower ifp->if_ibytes += m->m_pkthdr.len;
1555122Swnj splx(s);
1566544Sfeldman return (0);
1575122Swnj }
15813066Ssam
15948727Ssklower /* ARGSUSED */
16054718Ssklower void
lortrequest(cmd,rt,sa)16148727Ssklower lortrequest(cmd, rt, sa)
16252947Storek int cmd;
16352947Storek struct rtentry *rt;
16452947Storek struct sockaddr *sa;
16548727Ssklower {
16652947Storek
16748727Ssklower if (rt)
16848727Ssklower rt->rt_rmx.rmx_mtu = LOMTU;
16948727Ssklower }
17048727Ssklower
17113066Ssam /*
17213066Ssam * Process an ioctl request.
17313066Ssam */
17418370Skarels /* ARGSUSED */
17561362Sbostic int
loioctl(ifp,cmd,data)17613066Ssam loioctl(ifp, cmd, data)
17713066Ssam register struct ifnet *ifp;
178*68168Scgd u_long cmd;
17913066Ssam caddr_t data;
18013066Ssam {
18148727Ssklower register struct ifaddr *ifa;
18254718Ssklower register struct ifreq *ifr;
18354718Ssklower register int error = 0;
18413066Ssam
18513066Ssam switch (cmd) {
18613066Ssam
18713066Ssam case SIOCSIFADDR:
18818370Skarels ifp->if_flags |= IFF_UP;
18948727Ssklower ifa = (struct ifaddr *)data;
19048727Ssklower if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
19148727Ssklower ifa->ifa_rtrequest = lortrequest;
19218370Skarels /*
19318370Skarels * Everything else is done at a higher level.
19418370Skarels */
19513066Ssam break;
19613066Ssam
19754718Ssklower case SIOCADDMULTI:
19854718Ssklower case SIOCDELMULTI:
19954718Ssklower ifr = (struct ifreq *)data;
20054718Ssklower if (ifr == 0) {
20154718Ssklower error = EAFNOSUPPORT; /* XXX */
20254718Ssklower break;
20354718Ssklower }
20454718Ssklower switch (ifr->ifr_addr.sa_family) {
20554718Ssklower
20654718Ssklower #ifdef INET
20754718Ssklower case AF_INET:
20854718Ssklower break;
20954718Ssklower #endif
21054718Ssklower
21154718Ssklower default:
21254718Ssklower error = EAFNOSUPPORT;
21354718Ssklower break;
21454718Ssklower }
21554718Ssklower break;
21654718Ssklower
21713066Ssam default:
21813066Ssam error = EINVAL;
21913066Ssam }
22013066Ssam return (error);
22113066Ssam }
222