xref: /original-bsd/sys/net/raw_usrreq.c (revision b1f5c9f5)
1 /*	raw_usrreq.c	4.8	82/03/05	*/
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 /*
16  * Initialize raw connection block q.
17 */
18 raw_init()
19 {
20 COUNT(RAW_INIT);
21 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
22 }
23 
24 /*
25  * Raw protocol interface.
26  */
27 raw_input(m0, pf, daf, saf)
28 	struct mbuf *m0;
29 	struct sockproto *pf;
30 	struct sockaddr *daf, *saf;
31 {
32 	register struct mbuf *m;
33 	struct raw_header *rh;
34 	int s;
35 
36 COUNT(RAW_INPUT);
37 	/*
38 	 * Rip off an mbuf for a generic header.
39 	 */
40 	m = m_get(M_DONTWAIT);
41 	if (m == 0) {
42 		m_freem(m0);
43 		return;
44 	}
45 	m->m_next = m0;
46 	m->m_off = MMINOFF;
47 	m->m_len = sizeof(struct raw_header);
48 	rh = mtod(m, struct raw_header *);
49 	rh->raw_dst = *daf;
50 	rh->raw_src = *saf;
51 	rh->raw_protocol = *pf;
52 
53 	/*
54 	 * Header now contains enough info to decide
55 	 * which socket to place packet in (if any).
56 	 * Queue it up for the raw protocol process
57 	 * running at software interrupt level.
58 	 */
59 	s = splimp();
60 	IF_ENQUEUE(&rawintrq, m);
61 	splx(s);
62 	setrawintr();
63 }
64 
65 /*
66  * Raw protocol input routine.  Process packets entered
67  * into the queue at interrupt time.  Find the socket
68  * associated with the packet(s) and move them over.  If
69  * nothing exists for this packet, drop it.
70  */
71 rawintr()
72 {
73 	int s;
74 	struct mbuf *m;
75 	register struct rawcb *rp;
76 	register struct socket *so;
77 	register struct protosw *pr;
78 	register struct sockproto *sp;
79 	register struct sockaddr *sa;
80 	struct raw_header *rawp;
81 	struct socket *last;
82 
83 COUNT(RAWINTR);
84 next:
85 	s = splimp();
86 	IF_DEQUEUE(&rawintrq, m);
87 	splx(s);
88 	if (m == 0)
89 		return;
90 	rawp = mtod(m, struct raw_header *);
91 	sp = &rawp->raw_protocol;
92 	sa = &rawp->raw_dst;
93 
94 	/*
95 	 * Find the appropriate socket(s) in which to place this
96 	 * packet.  This is done by matching the protocol and
97 	 * address information prepended by raw_input against
98 	 * the info stored in the control block structures.
99 	 */
100 	last = 0;
101 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
102 		so = rp->rcb_socket;
103 		pr = so->so_proto;
104 		if (pr->pr_family != sp->sp_family ||
105 		    (pr->pr_protocol && pr->pr_protocol != sp->sp_protocol))
106 			continue;
107 		if (so->so_addr.sa_family &&
108 		    sa->sa_family != so->so_addr.sa_family)
109 			continue;
110 		/*
111 		 * We assume the lower level routines have
112 		 * placed the address in a canonical format
113 		 * suitable for a structure comparison. Packets
114 		 * are duplicated for each receiving socket.
115 		 *
116 		 * SHOULD HAVE A NUMBER OF MECHANISMS FOR
117 		 * MATCHING BASED ON rcb_flags
118 		 */
119 		if ((rp->rcb_flags & RAW_ADDR) &&
120 		    bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0)
121 			continue;
122 		/*
123 		 * To avoid extraneous packet copies, we keep
124 		 * track of the last socket the packet should be
125 		 * placed in, and make copies only after finding a
126 		 * socket which "collides".
127 		 */
128 		if (last) {
129 			struct mbuf *n;
130 
131 			if (n = m_copy(m->m_next, 0, M_COPYALL))
132 				goto nospace;
133 			if (sbappendaddr(&last->so_rcv, &rawp->raw_src, n) == 0) {
134 				/*
135 				 * Should drop notification of lost packet
136 				 * into this guy's queue, but...
137 				 */
138 				m_freem(n);
139 				goto nospace;
140 			}
141 			sorwakeup(last);
142 		}
143 nospace:
144 		last = so;
145 	}
146 	if (last == 0)
147 		goto drop;
148 	if (sbappendaddr(&last->so_rcv, &rawp->raw_src, m->m_next) == 0)
149 {
150 printf("rawintr: sbappendaddr failed\n");
151 		goto drop;
152 }
153 	(void) m_free(m);	/* generic header */
154 	sorwakeup(last);
155 	goto next;
156 drop:
157 	m_freem(m);
158 	goto next;
159 }
160 
161 /*ARGSUSED*/
162 raw_usrreq(so, req, m, addr)
163 	struct socket *so;
164 	int req;
165 	struct mbuf *m;
166 	caddr_t addr;
167 {
168 	register struct rawcb *rp = sotorawcb(so);
169 	int error = 0;
170 
171 COUNT(RAW_USRREQ);
172 	if (rp == 0 && req != PRU_ATTACH)
173 		return (EINVAL);
174 
175 	switch (req) {
176 
177 	/*
178 	 * Allocate a raw control block and fill in the
179 	 * necessary info to allow packets to be routed to
180 	 * the appropriate raw interface routine.
181 	 */
182 	case PRU_ATTACH:
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_ADDR)
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_ADDR) == 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_ADDR)
232 				return (EISCONN);
233 			raw_connaddr(rp, (struct sockaddr *)addr);
234 		} else if ((rp->rcb_flags & RAW_ADDR) == 0)
235 			return (ENOTCONN);
236 		(void) (*so->so_proto->pr_output)(m, so);
237 		if (addr)
238 			rp->rcb_flags &= ~RAW_ADDR;
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 	default:
260 		panic("raw_usrreq");
261 	}
262 	return (error);
263 }
264