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