xref: /original-bsd/sys/net/raw_usrreq.c (revision 8208c1e2)
1 /*	raw_usrreq.c	4.11	82/03/19	*/
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, pf, daf, saf)
32 	struct mbuf *m0;
33 	struct sockproto *pf;
34 	struct sockaddr *daf, *saf;
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 = *daf;
54 	rh->raw_src = *saf;
55 	rh->raw_protocol = *pf;
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 socket *so;
84 	register struct protosw *pr;
85 	register struct sockproto *sp;
86 	register struct sockaddr *sa;
87 	struct raw_header *rawp;
88 	struct socket *last;
89 
90 COUNT(RAWINTR);
91 next:
92 	s = splimp();
93 	IF_DEQUEUE(&rawintrq, m);
94 	splx(s);
95 	if (m == 0)
96 		return;
97 	rawp = mtod(m, struct raw_header *);
98 	sp = &rawp->raw_protocol;
99 	sa = &rawp->raw_dst;
100 
101 	/*
102 	 * Find the appropriate socket(s) in which to place this
103 	 * packet.  This is done by matching the protocol and
104 	 * address information prepended by raw_input against
105 	 * the info stored in the control block structures.
106 	 */
107 	last = 0;
108 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
109 		so = rp->rcb_socket;
110 		pr = so->so_proto;
111 		if (pr->pr_family != sp->sp_family ||
112 		    (pr->pr_protocol && pr->pr_protocol != sp->sp_protocol))
113 			continue;
114 		if (so->so_addr.sa_family &&
115 		    sa->sa_family != so->so_addr.sa_family)
116 			continue;
117 		/*
118 		 * We assume the lower level routines have
119 		 * placed the address in a canonical format
120 		 * suitable for a structure comparison. Packets
121 		 * are duplicated for each receiving socket.
122 		 *
123 		 * SHOULD HAVE A NUMBER OF MECHANISMS FOR
124 		 * MATCHING BASED ON rcb_flags
125 		 */
126 		if ((rp->rcb_flags & RAW_ADDR) &&
127 		    bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0)
128 			continue;
129 		/*
130 		 * To avoid extraneous packet copies, we keep
131 		 * track of the last socket the packet should be
132 		 * placed in, and make copies only after finding a
133 		 * socket which "collides".
134 		 */
135 		if (last) {
136 			struct mbuf *n;
137 
138 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL))
139 				goto nospace;
140 			if (sbappendaddr(&last->so_rcv, &rawp->raw_src, n) == 0) {
141 				/*
142 				 * Should drop notification of lost packet
143 				 * into this guy's queue, but...
144 				 */
145 				m_freem(n);
146 				goto nospace;
147 			}
148 			sorwakeup(last);
149 		}
150 nospace:
151 		last = so;
152 	}
153 	if (last == 0)
154 		goto drop;
155 	if (sbappendaddr(&last->so_rcv, &rawp->raw_src, m->m_next) == 0)
156 {
157 printf("rawintr: sbappendaddr failed\n");
158 		goto drop;
159 }
160 	(void) m_free(m);	/* generic header */
161 	sorwakeup(last);
162 	goto next;
163 drop:
164 	m_freem(m);
165 	goto next;
166 }
167 
168 /*ARGSUSED*/
169 raw_usrreq(so, req, m, addr)
170 	struct socket *so;
171 	int req;
172 	struct mbuf *m;
173 	caddr_t addr;
174 {
175 	register struct rawcb *rp = sotorawcb(so);
176 	int error = 0;
177 
178 COUNT(RAW_USRREQ);
179 	if (rp == 0 && req != PRU_ATTACH)
180 		return (EINVAL);
181 
182 	switch (req) {
183 
184 	/*
185 	 * Allocate a raw control block and fill in the
186 	 * necessary info to allow packets to be routed to
187 	 * the appropriate raw interface routine.
188 	 */
189 	case PRU_ATTACH:
190 		if ((so->so_state & SS_PRIV) == 0)
191 			return (EPERM);
192 		if (rp)
193 			return (EINVAL);
194 		error = raw_attach(so, (struct sockaddr *)addr);
195 		break;
196 
197 	/*
198 	 * Destroy state just before socket deallocation.
199 	 * Flush data or not depending on the options.
200 	 */
201 	case PRU_DETACH:
202 		if (rp == 0)
203 			return (ENOTCONN);
204 		raw_detach(rp);
205 		break;
206 
207 	/*
208 	 * If a socket isn't bound to a single address,
209 	 * the raw input routine will hand it anything
210 	 * within that protocol family (assuming there's
211 	 * nothing else around it should go to).
212 	 */
213 	case PRU_CONNECT:
214 		if (rp->rcb_flags & RAW_ADDR)
215 			return (EISCONN);
216 		raw_connaddr(rp, (struct sockaddr *)addr);
217 		soisconnected(so);
218 		break;
219 
220 	case PRU_DISCONNECT:
221 		if ((rp->rcb_flags & RAW_ADDR) == 0)
222 			return (ENOTCONN);
223 		raw_disconnect(rp);
224 		soisdisconnected(so);
225 		break;
226 
227 	/*
228 	 * Mark the connection as being incapable of further input.
229 	 */
230 	case PRU_SHUTDOWN:
231 		socantsendmore(so);
232 		break;
233 
234 	/*
235 	 * Ship a packet out.  The appropriate raw output
236 	 * routine handles any massaging necessary.
237 	 */
238 	case PRU_SEND:
239 		if (addr) {
240 			if (rp->rcb_flags & RAW_ADDR)
241 				return (EISCONN);
242 			raw_connaddr(rp, (struct sockaddr *)addr);
243 		} else if ((rp->rcb_flags & RAW_ADDR) == 0)
244 			return (ENOTCONN);
245 		(void) (*so->so_proto->pr_output)(m, so);
246 		if (addr)
247 			rp->rcb_flags &= ~RAW_ADDR;
248 		break;
249 
250 	case PRU_ABORT:
251 		raw_disconnect(rp);
252 		sofree(so);
253 		soisdisconnected(so);
254 		break;
255 
256 	/*
257 	 * Not supported.
258 	 */
259 	case PRU_ACCEPT:
260 	case PRU_RCVD:
261 	case PRU_CONTROL:
262 	case PRU_SENSE:
263 	case PRU_RCVOOB:
264 	case PRU_SENDOOB:
265 		error = EOPNOTSUPP;
266 		break;
267 
268 	default:
269 		panic("raw_usrreq");
270 	}
271 	return (error);
272 }
273