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