ddp_usrreq.c revision 137386
1/*
2 * Copyright (c) 2004 Robert N. M. Watson
3 * Copyright (c) 1990,1994 Regents of The University of Michigan.
4 * All Rights Reserved.  See COPYRIGHT.
5 *
6 * $FreeBSD: head/sys/netatalk/ddp_usrreq.c 137386 2004-11-08 14:44:54Z phk $
7 */
8
9#include <sys/param.h>
10#include <sys/systm.h>
11#include <sys/malloc.h>
12#include <sys/mbuf.h>
13#include <sys/socket.h>
14#include <sys/socketvar.h>
15#include <sys/protosw.h>
16#include <net/if.h>
17#include <net/route.h>
18#include <net/netisr.h>
19
20#include <netatalk/at.h>
21#include <netatalk/at_var.h>
22#include <netatalk/ddp_var.h>
23#include <netatalk/ddp_pcb.h>
24#include <netatalk/at_extern.h>
25
26static u_long	ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
27static u_long	ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at));
28
29static struct ifqueue atintrq1, atintrq2, aarpintrq;
30
31static int
32ddp_attach(struct socket *so, int proto, struct thread *td)
33{
34	struct ddpcb	*ddp;
35	int		error = 0;
36
37	ddp = sotoddpcb(so);
38	if (ddp != NULL)
39		return (EINVAL);
40
41	/*
42	 * Allocate socket buffer space first so that it's present
43	 * before first use.
44	 */
45	error = soreserve(so, ddp_sendspace, ddp_recvspace);
46	if (error)
47		return (error);
48
49	DDP_LIST_XLOCK();
50	error = at_pcballoc(so);
51	DDP_LIST_XUNLOCK();
52	return (error);
53}
54
55static int
56ddp_detach(struct socket *so)
57{
58	struct ddpcb	*ddp;
59
60	ddp = sotoddpcb(so);
61	if (ddp == NULL)
62	    return (EINVAL);
63
64	DDP_LIST_XLOCK();
65	DDP_LOCK(ddp);
66	at_pcbdetach(so, ddp);
67	DDP_LIST_XUNLOCK();
68	return (0);
69}
70
71static int
72ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
73{
74	struct ddpcb	*ddp;
75	int		error = 0;
76
77	ddp = sotoddpcb(so);
78	if (ddp == NULL) {
79	    return (EINVAL);
80	}
81	DDP_LIST_XLOCK();
82	DDP_LOCK(ddp);
83	error = at_pcbsetaddr(ddp, nam, td);
84	DDP_UNLOCK(ddp);
85	DDP_LIST_XUNLOCK();
86	return (error);
87}
88
89static int
90ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
91{
92	struct ddpcb	*ddp;
93	int		error = 0;
94
95	ddp = sotoddpcb(so);
96	if (ddp == NULL) {
97	    return (EINVAL);
98	}
99
100	DDP_LIST_XLOCK();
101	DDP_LOCK(ddp);
102	if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
103	    DDP_UNLOCK(ddp);
104	    DDP_LIST_XUNLOCK();
105	    return (EISCONN);
106	}
107
108	error = at_pcbconnect( ddp, nam, td );
109	DDP_UNLOCK(ddp);
110	DDP_LIST_XUNLOCK();
111	if (error == 0)
112	    soisconnected(so);
113	return (error);
114}
115
116static int
117ddp_disconnect(struct socket *so)
118{
119
120	struct ddpcb	*ddp;
121
122	ddp = sotoddpcb(so);
123	if (ddp == NULL) {
124	    return (EINVAL);
125	}
126	DDP_LOCK(ddp);
127	if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
128	    DDP_UNLOCK(ddp);
129	    return (ENOTCONN);
130	}
131
132	at_pcbdisconnect(ddp);
133	ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
134	DDP_UNLOCK(ddp);
135	soisdisconnected(so);
136	return (0);
137}
138
139static int
140ddp_shutdown(struct socket *so)
141{
142	struct ddpcb	*ddp;
143
144	ddp = sotoddpcb(so);
145	if (ddp == NULL) {
146		return (EINVAL);
147	}
148	socantsendmore(so);
149	return (0);
150}
151
152static int
153ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
154            struct mbuf *control, struct thread *td)
155{
156	struct ddpcb	*ddp;
157	int		error = 0;
158
159	ddp = sotoddpcb(so);
160	if (ddp == NULL) {
161		return (EINVAL);
162	}
163
164    	if (control && control->m_len) {
165		return (EINVAL);
166    	}
167
168	if (addr != NULL) {
169		DDP_LIST_XLOCK();
170		DDP_LOCK(ddp);
171		if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
172			error = EISCONN;
173			goto out;
174		}
175
176		error = at_pcbconnect(ddp, addr, td);
177		if (error == 0) {
178			error = ddp_output(m, so);
179			at_pcbdisconnect(ddp);
180		}
181out:
182		DDP_UNLOCK(ddp);
183		DDP_LIST_XUNLOCK();
184	} else {
185		DDP_LOCK(ddp);
186		if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT)
187			error = ENOTCONN;
188		else
189			error = ddp_output(m, so);
190		DDP_UNLOCK(ddp);
191	}
192	return (error);
193}
194
195static int
196ddp_abort(struct socket *so)
197{
198	struct ddpcb	*ddp;
199
200	ddp = sotoddpcb(so);
201	if (ddp == NULL) {
202		return (EINVAL);
203	}
204	DDP_LIST_XLOCK();
205	DDP_LOCK(ddp);
206	at_pcbdetach(so, ddp);
207	DDP_LIST_XUNLOCK();
208	return (0);
209}
210
211void
212ddp_init(void)
213{
214	atintrq1.ifq_maxlen = IFQ_MAXLEN;
215	atintrq2.ifq_maxlen = IFQ_MAXLEN;
216	aarpintrq.ifq_maxlen = IFQ_MAXLEN;
217	mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF);
218	mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF);
219	mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF);
220	DDP_LIST_LOCK_INIT();
221	netisr_register(NETISR_ATALK1, at1intr, &atintrq1, 0);
222	netisr_register(NETISR_ATALK2, at2intr, &atintrq2, 0);
223	netisr_register(NETISR_AARP, aarpintr, &aarpintrq, 0);
224}
225
226#if 0
227static void
228ddp_clean(void)
229{
230    struct ddpcb	*ddp;
231
232    for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) {
233	at_pcbdetach(ddp->ddp_socket, ddp);
234    }
235    DDP_LIST_LOCK_DESTROY();
236}
237#endif
238
239static int
240at_setpeeraddr(struct socket *so, struct sockaddr **nam)
241{
242	return (EOPNOTSUPP);
243}
244
245static int
246at_setsockaddr(struct socket *so, struct sockaddr **nam)
247{
248	struct ddpcb	*ddp;
249
250	ddp = sotoddpcb(so);
251	if (ddp == NULL) {
252	    return (EINVAL);
253	}
254	DDP_LOCK(ddp);
255	at_sockaddr(ddp, nam);
256	DDP_UNLOCK(ddp);
257	return (0);
258}
259
260struct pr_usrreqs ddp_usrreqs = {
261	.pru_abort =		ddp_abort,
262	.pru_attach =		ddp_attach,
263	.pru_bind =		ddp_bind,
264	.pru_connect =		ddp_connect,
265	.pru_control =		at_control,
266	.pru_detach =		ddp_detach,
267	.pru_disconnect =	ddp_disconnect,
268	.pru_peeraddr =		at_setpeeraddr,
269	.pru_send =		ddp_send,
270	.pru_shutdown =		ddp_shutdown,
271	.pru_sockaddr =		at_setsockaddr,
272};
273