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