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