xref: /csrg-svn/sys/net/if_loop.c (revision 29922)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)if_loop.c	7.2 (Berkeley) 10/28/86
7  */
8 
9 /*
10  * Loopback interface driver for protocol testing and timing.
11  */
12 
13 #include "param.h"
14 #include "systm.h"
15 #include "mbuf.h"
16 #include "socket.h"
17 #include "errno.h"
18 #include "ioctl.h"
19 
20 #include "../net/if.h"
21 #include "../net/netisr.h"
22 #include "../net/route.h"
23 
24 #include "../machine/mtpr.h"
25 
26 #ifdef	INET
27 #include "../netinet/in.h"
28 #include "../netinet/in_systm.h"
29 #include "../netinet/in_var.h"
30 #include "../netinet/ip.h"
31 #endif
32 
33 #ifdef NS
34 #include "../netns/ns.h"
35 #include "../netns/ns_if.h"
36 #endif
37 
38 #define	LOMTU	(1024+512)
39 
40 struct	ifnet loif;
41 int	looutput(), loioctl();
42 
43 loattach()
44 {
45 	register struct ifnet *ifp = &loif;
46 
47 	ifp->if_name = "lo";
48 	ifp->if_mtu = LOMTU;
49 	ifp->if_flags = IFF_LOOPBACK;
50 	ifp->if_ioctl = loioctl;
51 	ifp->if_output = looutput;
52 	if_attach(ifp);
53 }
54 
55 looutput(ifp, m0, dst)
56 	struct ifnet *ifp;
57 	register struct mbuf *m0;
58 	struct sockaddr *dst;
59 {
60 	int s;
61 	register struct ifqueue *ifq;
62 	struct mbuf *m;
63 
64 	/*
65 	 * Place interface pointer before the data
66 	 * for the receiving protocol.
67 	 */
68 	if (m0->m_off <= MMAXOFF &&
69 	    m0->m_off >= MMINOFF + sizeof(struct ifnet *)) {
70 		m0->m_off -= sizeof(struct ifnet *);
71 		m0->m_len += sizeof(struct ifnet *);
72 	} else {
73 		MGET(m, M_DONTWAIT, MT_HEADER);
74 		if (m == (struct mbuf *)0)
75 			return (ENOBUFS);
76 		m->m_off = MMINOFF;
77 		m->m_len = sizeof(struct ifnet *);
78 		m->m_next = m0;
79 		m0 = m;
80 	}
81 	*(mtod(m0, struct ifnet **)) = ifp;
82 	s = splimp();
83 	ifp->if_opackets++;
84 	switch (dst->sa_family) {
85 
86 #ifdef INET
87 	case AF_INET:
88 		ifq = &ipintrq;
89 		if (IF_QFULL(ifq)) {
90 			IF_DROP(ifq);
91 			m_freem(m0);
92 			splx(s);
93 			return (ENOBUFS);
94 		}
95 		IF_ENQUEUE(ifq, m0);
96 		schednetisr(NETISR_IP);
97 		break;
98 #endif
99 #ifdef NS
100 	case AF_NS:
101 		ifq = &nsintrq;
102 		if (IF_QFULL(ifq)) {
103 			IF_DROP(ifq);
104 			m_freem(m0);
105 			splx(s);
106 			return (ENOBUFS);
107 		}
108 		IF_ENQUEUE(ifq, m0);
109 		schednetisr(NETISR_NS);
110 		break;
111 #endif
112 	default:
113 		splx(s);
114 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
115 			dst->sa_family);
116 		m_freem(m0);
117 		return (EAFNOSUPPORT);
118 	}
119 	ifp->if_ipackets++;
120 	splx(s);
121 	return (0);
122 }
123 
124 /*
125  * Process an ioctl request.
126  */
127 /* ARGSUSED */
128 loioctl(ifp, cmd, data)
129 	register struct ifnet *ifp;
130 	int cmd;
131 	caddr_t data;
132 {
133 	int error = 0;
134 
135 	switch (cmd) {
136 
137 	case SIOCSIFADDR:
138 		ifp->if_flags |= IFF_UP;
139 		/*
140 		 * Everything else is done at a higher level.
141 		 */
142 		break;
143 
144 	default:
145 		error = EINVAL;
146 	}
147 	return (error);
148 }
149