xref: /csrg-svn/sys/net/if_loop.c (revision 33183)
123174Smckusick /*
229071Skarels  * Copyright (c) 1982, 1986 Regents of the University of California.
3*33183Sbostic  * All rights reserved.
423174Smckusick  *
5*33183Sbostic  * Redistribution and use in source and binary forms are permitted
6*33183Sbostic  * provided that this notice is preserved and that due credit is given
7*33183Sbostic  * to the University of California at Berkeley. The name of the University
8*33183Sbostic  * may not be used to endorse or promote products derived from this
9*33183Sbostic  * software without specific prior written permission. This software
10*33183Sbostic  * is provided ``as is'' without express or implied warranty.
11*33183Sbostic  *
12*33183Sbostic  *	@(#)if_loop.c	7.3 (Berkeley) 12/30/87
1323174Smckusick  */
145122Swnj 
155122Swnj /*
165122Swnj  * Loopback interface driver for protocol testing and timing.
175122Swnj  */
185122Swnj 
1917058Sbloom #include "param.h"
2017058Sbloom #include "systm.h"
2117058Sbloom #include "mbuf.h"
2217058Sbloom #include "socket.h"
2317058Sbloom #include "errno.h"
2417058Sbloom #include "ioctl.h"
2510907Ssam 
2610907Ssam #include "../net/if.h"
2710907Ssam #include "../net/netisr.h"
2810907Ssam #include "../net/route.h"
2910907Ssam 
3029922Skarels #include "../machine/mtpr.h"
3129922Skarels 
3224771Skarels #ifdef	INET
3324771Skarels #include "../netinet/in.h"
3424771Skarels #include "../netinet/in_systm.h"
3529071Skarels #include "../netinet/in_var.h"
3624771Skarels #include "../netinet/ip.h"
3724771Skarels #endif
385122Swnj 
3918815Ssklower #ifdef NS
4018815Ssklower #include "../netns/ns.h"
4118815Ssklower #include "../netns/ns_if.h"
4218815Ssklower #endif
4318815Ssklower 
445207Swnj #define	LOMTU	(1024+512)
455122Swnj 
465122Swnj struct	ifnet loif;
4713066Ssam int	looutput(), loioctl();
485122Swnj 
495122Swnj loattach()
505122Swnj {
515122Swnj 	register struct ifnet *ifp = &loif;
525122Swnj 
535172Swnj 	ifp->if_name = "lo";
545122Swnj 	ifp->if_mtu = LOMTU;
5526091Skarels 	ifp->if_flags = IFF_LOOPBACK;
5613066Ssam 	ifp->if_ioctl = loioctl;
575122Swnj 	ifp->if_output = looutput;
585161Swnj 	if_attach(ifp);
595122Swnj }
605122Swnj 
616337Ssam looutput(ifp, m0, dst)
625122Swnj 	struct ifnet *ifp;
6324771Skarels 	register struct mbuf *m0;
646337Ssam 	struct sockaddr *dst;
655122Swnj {
6624771Skarels 	int s;
676209Swnj 	register struct ifqueue *ifq;
6824771Skarels 	struct mbuf *m;
695122Swnj 
7024771Skarels 	/*
7124771Skarels 	 * Place interface pointer before the data
7224771Skarels 	 * for the receiving protocol.
7324771Skarels 	 */
7424771Skarels 	if (m0->m_off <= MMAXOFF &&
7524771Skarels 	    m0->m_off >= MMINOFF + sizeof(struct ifnet *)) {
7624771Skarels 		m0->m_off -= sizeof(struct ifnet *);
7724771Skarels 		m0->m_len += sizeof(struct ifnet *);
7824771Skarels 	} else {
7924771Skarels 		MGET(m, M_DONTWAIT, MT_HEADER);
8024771Skarels 		if (m == (struct mbuf *)0)
8124771Skarels 			return (ENOBUFS);
8224771Skarels 		m->m_off = MMINOFF;
8324771Skarels 		m->m_len = sizeof(struct ifnet *);
8424771Skarels 		m->m_next = m0;
8524771Skarels 		m0 = m;
8624771Skarels 	}
8724771Skarels 	*(mtod(m0, struct ifnet **)) = ifp;
8824771Skarels 	s = splimp();
895172Swnj 	ifp->if_opackets++;
906337Ssam 	switch (dst->sa_family) {
915122Swnj 
925122Swnj #ifdef INET
936337Ssam 	case AF_INET:
946209Swnj 		ifq = &ipintrq;
956209Swnj 		if (IF_QFULL(ifq)) {
966209Swnj 			IF_DROP(ifq);
976337Ssam 			m_freem(m0);
986209Swnj 			splx(s);
996544Sfeldman 			return (ENOBUFS);
1006209Swnj 		}
1016209Swnj 		IF_ENQUEUE(ifq, m0);
1026262Swnj 		schednetisr(NETISR_IP);
1035122Swnj 		break;
1045122Swnj #endif
10518815Ssklower #ifdef NS
10618815Ssklower 	case AF_NS:
10718815Ssklower 		ifq = &nsintrq;
10818815Ssklower 		if (IF_QFULL(ifq)) {
10918815Ssklower 			IF_DROP(ifq);
11018815Ssklower 			m_freem(m0);
11118815Ssklower 			splx(s);
11218815Ssklower 			return (ENOBUFS);
11318815Ssklower 		}
11418815Ssklower 		IF_ENQUEUE(ifq, m0);
11518815Ssklower 		schednetisr(NETISR_NS);
11618815Ssklower 		break;
11718815Ssklower #endif
1185122Swnj 	default:
1195122Swnj 		splx(s);
1206337Ssam 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
1216337Ssam 			dst->sa_family);
1226337Ssam 		m_freem(m0);
1236544Sfeldman 		return (EAFNOSUPPORT);
1245122Swnj 	}
1255172Swnj 	ifp->if_ipackets++;
1265122Swnj 	splx(s);
1276544Sfeldman 	return (0);
1285122Swnj }
12913066Ssam 
13013066Ssam /*
13113066Ssam  * Process an ioctl request.
13213066Ssam  */
13318370Skarels /* ARGSUSED */
13413066Ssam loioctl(ifp, cmd, data)
13513066Ssam 	register struct ifnet *ifp;
13613066Ssam 	int cmd;
13713066Ssam 	caddr_t data;
13813066Ssam {
13918370Skarels 	int error = 0;
14013066Ssam 
14113066Ssam 	switch (cmd) {
14213066Ssam 
14313066Ssam 	case SIOCSIFADDR:
14418370Skarels 		ifp->if_flags |= IFF_UP;
14518370Skarels 		/*
14618370Skarels 		 * Everything else is done at a higher level.
14718370Skarels 		 */
14813066Ssam 		break;
14913066Ssam 
15013066Ssam 	default:
15113066Ssam 		error = EINVAL;
15213066Ssam 	}
15313066Ssam 	return (error);
15413066Ssam }
155