1139827Simp/*-
2193219Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson
3165891Srwatson * All rights reserved.
4165891Srwatson *
5165891Srwatson * Redistribution and use in source and binary forms, with or without
6165891Srwatson * modification, are permitted provided that the following conditions
7165891Srwatson * are met:
8165891Srwatson * 1. Redistributions of source code must retain the above copyright
9165891Srwatson *    notice, this list of conditions and the following disclaimer.
10165891Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11165891Srwatson *    notice, this list of conditions and the following disclaimer in the
12165891Srwatson *    documentation and/or other materials provided with the distribution.
13165891Srwatson *
14165891Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15165891Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16165891Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17165891Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18165891Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19165891Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20165891Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21165891Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22165891Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23165891Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24165891Srwatson * SUCH DAMAGE.
25165891Srwatson *
26165974Srwatson * Copyright (c) 1990, 1994 Regents of The University of Michigan.
27139827Simp * All Rights Reserved.
2867893Sphk *
29139827Simp * Permission to use, copy, modify, and distribute this software and
30139827Simp * its documentation for any purpose and without fee is hereby granted,
31139827Simp * provided that the above copyright notice appears in all copies and
32139827Simp * that both that copyright notice and this permission notice appear
33139827Simp * in supporting documentation, and that the name of The University
34139827Simp * of Michigan not be used in advertising or publicity pertaining to
35139827Simp * distribution of the software without specific, written prior
36139827Simp * permission. This software is supplied as is without expressed or
37139827Simp * implied warranties of any kind.
38139827Simp *
39139827Simp * This product includes software developed by the University of
40139827Simp * California, Berkeley and its contributors.
41139827Simp *
42139827Simp *	Research Systems Unix Group
43139827Simp *	The University of Michigan
44139827Simp *	c/o Wesley Craig
45139827Simp *	535 W. William Street
46139827Simp *	Ann Arbor, Michigan
47139827Simp *	+1-313-764-2278
48139827Simp *	netatalk@umich.edu
49139827Simp *
5067893Sphk * $FreeBSD$
5115885Sjulian */
5215885Sjulian
5315885Sjulian#include <sys/param.h>
5415885Sjulian#include <sys/systm.h>
5529024Sbde#include <sys/malloc.h>
5615885Sjulian#include <sys/mbuf.h>
5715885Sjulian#include <sys/socket.h>
5815885Sjulian#include <sys/socketvar.h>
5915885Sjulian#include <sys/protosw.h>
6015885Sjulian#include <net/if.h>
6115885Sjulian#include <net/route.h>
62111888Sjlemon#include <net/netisr.h>
6315885Sjulian
6418207Sbde#include <netatalk/at.h>
6518207Sbde#include <netatalk/at_var.h>
6618207Sbde#include <netatalk/ddp_var.h>
67127195Srwatson#include <netatalk/ddp_pcb.h>
6815885Sjulian#include <netatalk/at_extern.h>
6915885Sjulian
7033181Seivindstatic u_long	ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
71127288Srwatsonstatic u_long	ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at));
7215885Sjulian
73193219Srwatsonstatic const struct netisr_handler atalk1_nh = {
74193219Srwatson	.nh_name = "atalk1",
75193219Srwatson	.nh_handler = at1intr,
76193219Srwatson	.nh_proto = NETISR_ATALK1,
77193219Srwatson	.nh_policy = NETISR_POLICY_SOURCE,
78193219Srwatson};
7925791Sjulian
80193219Srwatsonstatic const struct netisr_handler atalk2_nh = {
81193219Srwatson	.nh_name = "atalk2",
82193219Srwatson	.nh_handler = at2intr,
83193219Srwatson	.nh_proto = NETISR_ATALK2,
84193219Srwatson	.nh_policy = NETISR_POLICY_SOURCE,
85193219Srwatson};
86193219Srwatson
87193219Srwatsonstatic const struct netisr_handler aarp_nh = {
88193219Srwatson	.nh_name = "aarp",
89193219Srwatson	.nh_handler = aarpintr,
90193219Srwatson	.nh_proto = NETISR_AARP,
91193219Srwatson	.nh_policy = NETISR_POLICY_SOURCE,
92193219Srwatson};
93193219Srwatson
9425791Sjulianstatic int
9583366Sjulianddp_attach(struct socket *so, int proto, struct thread *td)
9615885Sjulian{
97165974Srwatson	int error = 0;
9825791Sjulian
99188124Srwatson	KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL"));
10025791Sjulian
101132043Srwatson	/*
102132043Srwatson	 * Allocate socket buffer space first so that it's present
103132043Srwatson	 * before first use.
104132043Srwatson	 */
105132043Srwatson	error = soreserve(so, ddp_sendspace, ddp_recvspace);
106132043Srwatson	if (error)
107132043Srwatson		return (error);
108132043Srwatson
109132043Srwatson	DDP_LIST_XLOCK();
110127288Srwatson	error = at_pcballoc(so);
111132043Srwatson	DDP_LIST_XUNLOCK();
112132043Srwatson	return (error);
11325791Sjulian}
11415885Sjulian
115157370Srwatsonstatic void
11625791Sjulianddp_detach(struct socket *so)
11725791Sjulian{
118165974Srwatson	struct ddpcb *ddp;
11925791Sjulian
120127288Srwatson	ddp = sotoddpcb(so);
121156817Srwatson	KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL"));
122132043Srwatson
123132043Srwatson	DDP_LIST_XLOCK();
124132043Srwatson	DDP_LOCK(ddp);
125127288Srwatson	at_pcbdetach(so, ddp);
126132043Srwatson	DDP_LIST_XUNLOCK();
12725791Sjulian}
12815885Sjulian
12925791Sjulianstatic int
13083366Sjulianddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
13125791Sjulian{
132165974Srwatson	struct ddpcb *ddp;
133165974Srwatson	int error = 0;
13425791Sjulian
135127288Srwatson	ddp = sotoddpcb(so);
136156817Srwatson	KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL"));
137157377Srwatson
138132043Srwatson	DDP_LIST_XLOCK();
139132043Srwatson	DDP_LOCK(ddp);
14083366Sjulian	error = at_pcbsetaddr(ddp, nam, td);
141132043Srwatson	DDP_UNLOCK(ddp);
142132043Srwatson	DDP_LIST_XUNLOCK();
14325791Sjulian	return (error);
14425791Sjulian}
14515885Sjulian
14625791Sjulianstatic int
14783366Sjulianddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
14825791Sjulian{
149165974Srwatson	struct ddpcb *ddp;
150165974Srwatson	int error = 0;
15125791Sjulian
152127288Srwatson	ddp = sotoddpcb(so);
153156817Srwatson	KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL"));
154157377Srwatson
155132043Srwatson	DDP_LIST_XLOCK();
156132043Srwatson	DDP_LOCK(ddp);
157127288Srwatson	if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
158165974Srwatson		DDP_UNLOCK(ddp);
159165974Srwatson		DDP_LIST_XUNLOCK();
160165974Srwatson		return (EISCONN);
16115885Sjulian	}
16215885Sjulian
163132043Srwatson	error = at_pcbconnect( ddp, nam, td );
164132043Srwatson	DDP_UNLOCK(ddp);
165132043Srwatson	DDP_LIST_XUNLOCK();
166127288Srwatson	if (error == 0)
167165974Srwatson		soisconnected(so);
168127288Srwatson	return (error);
16925791Sjulian}
17015885Sjulian
17125791Sjulianstatic int
17225791Sjulianddp_disconnect(struct socket *so)
17325791Sjulian{
174165974Srwatson	struct ddpcb *ddp;
17525791Sjulian
176127288Srwatson	ddp = sotoddpcb(so);
177156817Srwatson	KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL"));
178157377Srwatson
179132043Srwatson	DDP_LOCK(ddp);
180127288Srwatson	if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
181165974Srwatson		DDP_UNLOCK(ddp);
182165974Srwatson		return (ENOTCONN);
18315885Sjulian	}
18425791Sjulian
185127288Srwatson	at_pcbdisconnect(ddp);
18625791Sjulian	ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
187132043Srwatson	DDP_UNLOCK(ddp);
188127288Srwatson	soisdisconnected(so);
189127288Srwatson	return (0);
19025791Sjulian}
19115885Sjulian
19225791Sjulianstatic int
19325791Sjulianddp_shutdown(struct socket *so)
19425791Sjulian{
19541591Sarchie
196188124Srwatson	KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL"));
197157377Srwatson
198127288Srwatson	socantsendmore(so);
199127288Srwatson	return (0);
20025791Sjulian}
20115885Sjulian
20225791Sjulianstatic int
20328270Swollmanddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
204165974Srwatson    struct mbuf *control, struct thread *td)
20525791Sjulian{
206165974Srwatson	struct ddpcb *ddp;
207165974Srwatson	int error = 0;
20825791Sjulian
209127288Srwatson	ddp = sotoddpcb(so);
210156817Srwatson	KASSERT(ddp != NULL, ("ddp_send: ddp == NULL"));
21115885Sjulian
212157377Srwatson    	if (control && control->m_len)
213127288Srwatson		return (EINVAL);
21425791Sjulian
215127291Srwatson	if (addr != NULL) {
216132043Srwatson		DDP_LIST_XLOCK();
217132043Srwatson		DDP_LOCK(ddp);
218127288Srwatson		if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
219132043Srwatson			error = EISCONN;
220132043Srwatson			goto out;
22125791Sjulian		}
22215885Sjulian
22383366Sjulian		error = at_pcbconnect(ddp, addr, td);
224132043Srwatson		if (error == 0) {
225132043Srwatson			error = ddp_output(m, so);
226132043Srwatson			at_pcbdisconnect(ddp);
22725791Sjulian		}
228132043Srwatsonout:
229132043Srwatson		DDP_UNLOCK(ddp);
230132043Srwatson		DDP_LIST_XUNLOCK();
23115885Sjulian	} else {
232132043Srwatson		DDP_LOCK(ddp);
233132043Srwatson		if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT)
234132043Srwatson			error = ENOTCONN;
235132043Srwatson		else
236132043Srwatson			error = ddp_output(m, so);
237132043Srwatson		DDP_UNLOCK(ddp);
23815885Sjulian	}
239127288Srwatson	return (error);
24025791Sjulian}
24125791Sjulian
242160549Srwatson/*
243160549Srwatson * XXXRW: This is never called because we only invoke abort on stream
244160549Srwatson * protocols.
245160549Srwatson */
246157366Srwatsonstatic void
24725791Sjulianddp_abort(struct socket *so)
24825791Sjulian{
24925791Sjulian	struct ddpcb	*ddp;
25025791Sjulian
251127288Srwatson	ddp = sotoddpcb(so);
252156817Srwatson	KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL"));
253157377Srwatson
254132043Srwatson	DDP_LOCK(ddp);
255160549Srwatson	at_pcbdisconnect(ddp);
256160549Srwatson	DDP_UNLOCK(ddp);
257161002Srwatson	soisdisconnected(so);
25825791Sjulian}
25915885Sjulian
260160549Srwatsonstatic void
261160549Srwatsonddp_close(struct socket *so)
262160549Srwatson{
263160549Srwatson	struct ddpcb	*ddp;
264160549Srwatson
265160549Srwatson	ddp = sotoddpcb(so);
266160549Srwatson	KASSERT(ddp != NULL, ("ddp_close: ddp == NULL"));
267160549Srwatson
268160549Srwatson	DDP_LOCK(ddp);
269160549Srwatson	at_pcbdisconnect(ddp);
270160549Srwatson	DDP_UNLOCK(ddp);
271161002Srwatson	soisdisconnected(so);
272160549Srwatson}
273160549Srwatson
274127195Srwatsonvoid
275127195Srwatsonddp_init(void)
27615885Sjulian{
277165974Srwatson
278132043Srwatson	DDP_LIST_LOCK_INIT();
279194913Srwatson	TAILQ_INIT(&at_ifaddrhead);
280193219Srwatson	netisr_register(&atalk1_nh);
281193219Srwatson	netisr_register(&atalk2_nh);
282193219Srwatson	netisr_register(&aarp_nh);
28315885Sjulian}
28415885Sjulian
285127195Srwatson#if 0
28615885Sjulianstatic void
287127288Srwatsonddp_clean(void)
28815885Sjulian{
289165974Srwatson	struct ddpcp	*ddp;
29015885Sjulian
291165974Srwatson	for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next)
292165974Srwatson		at_pcbdetach(ddp->ddp_socket, ddp);
293165974Srwatson	DDP_LIST_LOCK_DESTROY();
29415885Sjulian}
295127195Srwatson#endif
29615885Sjulian
29725791Sjulianstatic int
298169462Srwatsonat_getpeeraddr(struct socket *so, struct sockaddr **nam)
29925791Sjulian{
300165974Srwatson
301127288Srwatson	return (EOPNOTSUPP);
30225791Sjulian}
30315885Sjulian
30425791Sjulianstatic int
305169462Srwatsonat_getsockaddr(struct socket *so, struct sockaddr **nam)
30625791Sjulian{
30725791Sjulian	struct ddpcb	*ddp;
30841591Sarchie
309127288Srwatson	ddp = sotoddpcb(so);
310169462Srwatson	KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL"));
311157130Srwatson
312132043Srwatson	DDP_LOCK(ddp);
313127288Srwatson	at_sockaddr(ddp, nam);
314132043Srwatson	DDP_UNLOCK(ddp);
315127288Srwatson	return (0);
31625791Sjulian}
31725791Sjulian
31825791Sjulianstruct pr_usrreqs ddp_usrreqs = {
319137386Sphk	.pru_abort =		ddp_abort,
320137386Sphk	.pru_attach =		ddp_attach,
321137386Sphk	.pru_bind =		ddp_bind,
322137386Sphk	.pru_connect =		ddp_connect,
323137386Sphk	.pru_control =		at_control,
324137386Sphk	.pru_detach =		ddp_detach,
325137386Sphk	.pru_disconnect =	ddp_disconnect,
326169462Srwatson	.pru_peeraddr =		at_getpeeraddr,
327137386Sphk	.pru_send =		ddp_send,
328137386Sphk	.pru_shutdown =		ddp_shutdown,
329169462Srwatson	.pru_sockaddr =		at_getsockaddr,
330160549Srwatson	.pru_close =		ddp_close,
33125791Sjulian};
332