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