xref: /csrg-svn/sys/net/raw_usrreq.c (revision 5612)
1 /*	raw_usrreq.c	4.5	82/01/24	*/
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, af)
28 	struct mbuf *m0;
29 	struct sockproto pf;
30 	struct sockaddr af;
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_address = af;
49 	rh->raw_protocol = pf;
50 
51 	/*
52 	 * Header now contains enough info to decide
53 	 * which socket to place packet in (if any).
54 	 * Queue it up for the raw protocol process
55 	 * running at software interrupt level.
56 	 */
57 	s = splimp();
58 	IF_ENQUEUE(&rawintrq, m);
59 	splx(s);
60 	setrawintr();
61 }
62 
63 /*
64  * Raw protocol input routine.  Process packets entered
65  * into the queue at interrupt time.  Find the socket
66  * associated with the packet(s) and move them over.  If
67  * nothing exists for this packet, drop it.
68  */
69 rawintr()
70 {
71 	int s;
72 	struct mbuf *m;
73 	register struct rawcb *rp;
74 	register struct socket *so;
75 	register struct protosw *pr;
76 	register struct sockproto *sp;
77 	register struct sockaddr *sa;
78 	struct socket *last;
79 
80 COUNT(RAWINTR);
81 next:
82 	s = splimp();
83 	IF_DEQUEUE(&rawintrq, m);
84 	splx(s);
85 	if (m == 0)
86 		return;
87 	sp = &(mtod(m, struct raw_header *)->raw_protocol);
88 	sa = &(mtod(m, struct raw_header *)->raw_address);
89 
90 	/*
91 	 * Find the appropriate socket(s) in which to place this
92 	 * packet.  This is done by matching the protocol and
93 	 * address information prepended by raw_input against
94 	 * the info stored in the control block structures.
95 	 */
96 	last = 0;
97 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
98 		so = rp->rcb_socket;
99 		pr = so->so_proto;
100 
101 		if (so->so_options & SO_DEBUG) {
102 			printf("rawintr: sp=<%d,%d>, af=<%d,%x>\n",
103 			 sp->sp_family, sp->sp_protocol, sa->sa_family,
104 			 ((struct sockaddr_in *)sa)->sin_addr);
105 			printf("pr=<%d,%d>\n", pr->pr_family, pr->pr_protocol);
106 		}
107 		if (pr->pr_family != sp->sp_family ||
108 		    pr->pr_protocol != sp->sp_protocol)
109 			continue;
110 		printf("rawintr: so=<%d,%x>\n", so->so_addr.sa_family,
111 			((struct sockaddr_in *)&so->so_addr)->sin_addr);
112 		if (sa->sa_family != so->so_addr.sa_family)
113 			continue;
114 		/*
115 		 * We assume the lower level routines have
116 		 * placed the address in a canonical format
117 		 * suitable for a structure comparison. Packets
118 		 * are duplicated for each receiving socket.
119 		 */
120 		if ((rp->rcb_flags & RAW_ADDR) &&
121 		    bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0)
122 			continue;
123 		/*
124 		 * To avoid extraneous packet copies, we keep
125 		 * track of the last socket the packet should be
126 		 * placed in, and make copies only after finding a
127 		 * socket which "collides".
128 		 */
129 		if (last) {
130 			struct mbuf *n;
131 
132 			if (n = m_copy(m->m_next, 0, M_COPYALL))
133 				goto nospace;
134 			sbappend(&last->so_rcv, n);
135 			sorwakeup(last);
136 		}
137 nospace:
138 		last = so;
139 	}
140 	if (last == 0)
141 		goto drop;
142 	m = m_free(m);		/* drop generic header */
143 	sbappend(&last->so_rcv, m->m_next);
144 	sorwakeup(last);
145 	goto next;
146 drop:
147 	m_freem(m);
148 	goto next;
149 }
150 
151 /*ARGSUSED*/
152 raw_usrreq(so, req, m, addr)
153 	struct socket *so;
154 	int req;
155 	struct mbuf *m;
156 	caddr_t addr;
157 {
158 	register struct rawcb *rp = sotorawcb(so);
159 	int error = 0;
160 
161 COUNT(RAW_USRREQ);
162 	if (so->so_options & SO_DEBUG)
163 		printf("raw_usrreq: req=%d\n");
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