xref: /csrg-svn/sys/net/raw_usrreq.c (revision 6509)
1 /*	raw_usrreq.c	4.13	82/04/10	*/
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/protosw.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../h/mtpr.h"
9 #include "../net/in.h"
10 #include "../net/in_systm.h"
11 #include "../net/if.h"
12 #include "../net/raw_cb.h"
13 #include <errno.h>
14 
15 int	rawqmaxlen = IFQ_MAXLEN;
16 
17 /*
18  * Initialize raw connection block q.
19  */
20 raw_init()
21 {
22 
23 COUNT(RAW_INIT);
24 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
25 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
26 }
27 
28 /*
29  * Raw protocol interface.
30  */
31 raw_input(m0, proto, dst, src)
32 	struct mbuf *m0;
33 	struct sockproto *proto;
34 	struct sockaddr *dst, *src;
35 {
36 	register struct mbuf *m;
37 	struct raw_header *rh;
38 	int s;
39 
40 COUNT(RAW_INPUT);
41 	/*
42 	 * Rip off an mbuf for a generic header.
43 	 */
44 	m = m_get(M_DONTWAIT);
45 	if (m == 0) {
46 		m_freem(m0);
47 		return;
48 	}
49 	m->m_next = m0;
50 	m->m_off = MMINOFF;
51 	m->m_len = sizeof(struct raw_header);
52 	rh = mtod(m, struct raw_header *);
53 	rh->raw_dst = *dst;
54 	rh->raw_src = *src;
55 	rh->raw_proto = *proto;
56 
57 	/*
58 	 * Header now contains enough info to decide
59 	 * which socket to place packet in (if any).
60 	 * Queue it up for the raw protocol process
61 	 * running at software interrupt level.
62 	 */
63 	s = splimp();
64 	if (IF_QFULL(&rawintrq))
65 		m_freem(m);
66 	else
67 		IF_ENQUEUE(&rawintrq, m);
68 	splx(s);
69 	schednetisr(NETISR_RAW);
70 }
71 
72 /*
73  * Raw protocol input routine.  Process packets entered
74  * into the queue at interrupt time.  Find the socket
75  * associated with the packet(s) and move them over.  If
76  * nothing exists for this packet, drop it.
77  */
78 rawintr()
79 {
80 	int s;
81 	struct mbuf *m;
82 	register struct rawcb *rp;
83 	register struct sockaddr *laddr;
84 	register struct protosw *lproto;
85 	struct raw_header *rh;
86 	struct socket *last;
87 
88 COUNT(RAWINTR);
89 next:
90 	s = splimp();
91 	IF_DEQUEUE(&rawintrq, m);
92 	splx(s);
93 	if (m == 0)
94 		return;
95 	rh = mtod(m, struct raw_header *);
96 
97 	/*
98 	 * Find the appropriate socket(s) in which to place this
99 	 * packet.  This is done by matching the protocol and
100 	 * address information prepended by raw_input against
101 	 * the info stored in the control block structures.
102 	 */
103 	last = 0;
104 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
105 		lproto = rp->rcb_socket->so_proto;
106 		if (lproto->pr_family != rh->raw_proto.sp_family)
107 			continue;
108 		if (lproto->pr_protocol &&
109 		    lproto->pr_protocol != rh->raw_proto.sp_protocol)
110 			continue;
111 		laddr = &rp->rcb_laddr;
112 		if (laddr->sa_family &&
113 		    laddr->sa_family != rh->raw_dst.sa_family)
114 			continue;
115 		/*
116 		 * We assume the lower level routines have
117 		 * placed the address in a canonical format
118 		 * suitable for a structure comparison.
119 		 */
120 		if ((rp->rcb_flags & RAW_LADDR) &&
121 		    bcmp(laddr->sa_data, rh->raw_dst.sa_data, 14) != 0)
122 			continue;
123 		if ((rp->rcb_flags & RAW_FADDR) &&
124 		    bcmp(rp->rcb_faddr.sa_data, rh->raw_src.sa_data, 14) != 0)
125 			continue;
126 		/*
127 		 * To avoid extraneous packet copies, we keep
128 		 * track of the last socket the packet should be
129 		 * placed in, and make copies only after finding a
130 		 * socket which "collides".
131 		 */
132 		if (last) {
133 			struct mbuf *n;
134 
135 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL))
136 				goto nospace;
137 			if (sbappendaddr(&last->so_rcv, &rh->raw_src, n)==0) {
138 				/* should notify about lost packet */
139 				m_freem(n);
140 				goto nospace;
141 			}
142 			sorwakeup(last);
143 		}
144 nospace:
145 		last = rp->rcb_socket;
146 	}
147 	if (last == 0)
148 		goto drop;
149 	m = m_free(m);		/* header */
150 	if (sbappendaddr(&last->so_rcv, &rh->raw_src, m) == 0)
151 		goto drop;
152 	sorwakeup(last);
153 	goto next;
154 drop:
155 	m_freem(m);
156 	goto next;
157 }
158 
159 /*ARGSUSED*/
160 raw_usrreq(so, req, m, addr)
161 	struct socket *so;
162 	int req;
163 	struct mbuf *m;
164 	caddr_t addr;
165 {
166 	register struct rawcb *rp = sotorawcb(so);
167 	int error = 0;
168 
169 COUNT(RAW_USRREQ);
170 	if (rp == 0 && req != PRU_ATTACH)
171 		return (EINVAL);
172 
173 	switch (req) {
174 
175 	/*
176 	 * Allocate a raw control block and fill in the
177 	 * necessary info to allow packets to be routed to
178 	 * the appropriate raw interface routine.
179 	 */
180 	case PRU_ATTACH:
181 		if ((so->so_state & SS_PRIV) == 0)
182 			return (EPERM);
183 		if (rp)
184 			return (EINVAL);
185 		error = raw_attach(so, (struct sockaddr *)addr);
186 		break;
187 
188 	/*
189 	 * Destroy state just before socket deallocation.
190 	 * Flush data or not depending on the options.
191 	 */
192 	case PRU_DETACH:
193 		if (rp == 0)
194 			return (ENOTCONN);
195 		raw_detach(rp);
196 		break;
197 
198 	/*
199 	 * If a socket isn't bound to a single address,
200 	 * the raw input routine will hand it anything
201 	 * within that protocol family (assuming there's
202 	 * nothing else around it should go to).
203 	 */
204 	case PRU_CONNECT:
205 		if (rp->rcb_flags & RAW_FADDR)
206 			return (EISCONN);
207 		raw_connaddr(rp, (struct sockaddr *)addr);
208 		soisconnected(so);
209 		break;
210 
211 	case PRU_DISCONNECT:
212 		if ((rp->rcb_flags & RAW_FADDR) == 0)
213 			return (ENOTCONN);
214 		raw_disconnect(rp);
215 		soisdisconnected(so);
216 		break;
217 
218 	/*
219 	 * Mark the connection as being incapable of further input.
220 	 */
221 	case PRU_SHUTDOWN:
222 		socantsendmore(so);
223 		break;
224 
225 	/*
226 	 * Ship a packet out.  The appropriate raw output
227 	 * routine handles any massaging necessary.
228 	 */
229 	case PRU_SEND:
230 		if (addr) {
231 			if (rp->rcb_flags & RAW_FADDR)
232 				return (EISCONN);
233 			raw_connaddr(rp, (struct sockaddr *)addr);
234 		} else if ((rp->rcb_flags & RAW_FADDR) == 0)
235 			return (ENOTCONN);
236 		error = (*so->so_proto->pr_output)(m, so);
237 		if (addr)
238 			rp->rcb_flags &= ~RAW_FADDR;
239 		break;
240 
241 	case PRU_ABORT:
242 		raw_disconnect(rp);
243 		sofree(so);
244 		soisdisconnected(so);
245 		break;
246 
247 	/*
248 	 * Not supported.
249 	 */
250 	case PRU_ACCEPT:
251 	case PRU_RCVD:
252 	case PRU_CONTROL:
253 	case PRU_SENSE:
254 	case PRU_RCVOOB:
255 	case PRU_SENDOOB:
256 		error = EOPNOTSUPP;
257 		break;
258 
259 	case PRU_SOCKADDR:
260 		bcopy(addr, (caddr_t)&rp->rcb_laddr, sizeof (struct sockaddr));
261 		break;
262 
263 	default:
264 		panic("raw_usrreq");
265 	}
266 	return (error);
267 }
268