natm.c revision 160549
118334Speter/*	$NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $	*/
290075Sobrien/*-
318334Speter *
418334Speter * Copyright (c) 1996 Charles D. Cranor and Washington University.
590075Sobrien * Copyright (c) 2005-2006 Robert N. M. Watson
618334Speter * All rights reserved.
790075Sobrien *
890075Sobrien * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1118334Speter * 1. Redistributions of source code must retain the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1618334Speter * 3. All advertising materials mentioning features or use of this software
1718334Speter *    must display the following acknowledgement:
1890075Sobrien *      This product includes software developed by Charles D. Cranor and
1990075Sobrien *      Washington University.
2090075Sobrien * 4. The name of the author may not be used to endorse or promote products
2118334Speter *    derived from this software without specific prior written permission.
2218334Speter *
2318334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2450397Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2518334Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2690075Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2790075Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2818334Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2918334Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3018334Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3118334Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3218334Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3318334Speter */
3418334Speter
3518334Speter/*
3618334Speter * natm.c: Native mode ATM access (both aal0 and aal5).
3718334Speter */
3818334Speter
3918334Speter#include <sys/cdefs.h>
4018334Speter__FBSDID("$FreeBSD: head/sys/netnatm/natm.c 160549 2006-07-21 17:11:15Z rwatson $");
4118334Speter
4218334Speter#include <sys/param.h>
4318334Speter#include <sys/conf.h>
4418334Speter#include <sys/kernel.h>
4518334Speter#include <sys/lock.h>
4618334Speter#include <sys/malloc.h>
4718334Speter#include <sys/mbuf.h>
4818334Speter#include <sys/protosw.h>
4918334Speter#include <sys/signalvar.h>
5018334Speter#include <sys/socket.h>
5118334Speter#include <sys/socketvar.h>
5290075Sobrien#include <sys/sockio.h>
5390075Sobrien#include <sys/sx.h>
5490075Sobrien#include <sys/systm.h>
5590075Sobrien#include <sys/sysctl.h>
5690075Sobrien
5750397Sobrien#include <net/if.h>
5850397Sobrien#include <net/if_atm.h>
5918334Speter#include <net/netisr.h>
6018334Speter
6118334Speter#include <netinet/in.h>
6218334Speter
6318334Speter#include <netnatm/natm.h>
6418334Speter
6518334Speterstatic const u_long	natm5_sendspace = 16*1024;
6618334Speterstatic const u_long	natm5_recvspace = 16*1024;
6718334Speter
6818334Speterstatic const u_long	natm0_sendspace = 16*1024;
6918334Speterstatic const u_long	natm0_recvspace = 16*1024;
7018334Speter
7118334Speter/*
7218334Speter * netnatm global subsystem lock, protects all global data structures in
7318334Speter * netnatm.
7418334Speter */
7518334Speterstruct mtx	natm_mtx;
7618334Speter
7718334Speter/*
7818334Speter * User socket requests.
7990075Sobrien */
8018334Speterstatic int	natm_usr_attach(struct socket *, int, d_thread_t *);
8118334Speterstatic void	natm_usr_detach(struct socket *);
8290075Sobrienstatic int	natm_usr_connect(struct socket *, struct sockaddr *,
8318334Speter		    d_thread_t *);
8418334Speterstatic int	natm_usr_disconnect(struct socket *);
8518334Speterstatic int	natm_usr_shutdown(struct socket *);
8618334Speterstatic int	natm_usr_send(struct socket *, int, struct mbuf *,
8718334Speter		    struct sockaddr *, struct mbuf *, d_thread_t *);
8818334Speterstatic int	natm_usr_peeraddr(struct socket *, struct sockaddr **);
89117395Skanstatic int	natm_usr_control(struct socket *, u_long, caddr_t,
9090075Sobrien		    struct ifnet *, d_thread_t *);
9118334Speterstatic void	natm_usr_abort(struct socket *);
9218334Speterstatic int	natm_usr_bind(struct socket *, struct sockaddr *,
9318334Speter		    d_thread_t *);
9418334Speterstatic int	natm_usr_sockaddr(struct socket *, struct sockaddr **);
95117395Skan
96117395Skanstatic int
9790075Sobriennatm_usr_attach(struct socket *so, int proto, d_thread_t *p)
9890075Sobrien{
9918334Speter	struct natmpcb *npcb;
10018334Speter	int error = 0;
10118334Speter
10218334Speter	npcb = (struct natmpcb *)so->so_pcb;
103117395Skan	KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL"));
10418334Speter
105117395Skan	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
106117395Skan		if (proto == PROTO_NATMAAL5)
107117395Skan			error = soreserve(so, natm5_sendspace,
108117395Skan			    natm5_recvspace);
10918334Speter		else
110117395Skan			error = soreserve(so, natm0_sendspace,
11118334Speter			    natm0_recvspace);
11218334Speter		if (error)
113117395Skan			return (error);
11490075Sobrien	}
11590075Sobrien	so->so_pcb = npcb = npcb_alloc(M_WAITOK);
11618334Speter	npcb->npcb_socket = so;
11718334Speter	return (error);
11818334Speter}
11918334Speter
12018334Speterstatic void
12118334Speternatm_usr_detach(struct socket *so)
122117395Skan{
123117395Skan	struct natmpcb *npcb;
124117395Skan
125117395Skan	npcb = (struct natmpcb *)so->so_pcb;
126117395Skan	KASSERT(npcb != NULL, ("natm_usr_detach: npcb == NULL"));
127117395Skan
12818334Speter	NATM_LOCK();
12918334Speter	npcb_free(npcb, NPCB_DESTROY);	/* drain */
13018334Speter	so->so_pcb = NULL;
13118334Speter	NATM_UNLOCK();
13218334Speter}
13318334Speter
13418334Speterstatic int
13518334Speternatm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p)
13618334Speter{
13718334Speter	struct natmpcb *npcb;
13818334Speter	struct sockaddr_natm *snatm;
13918334Speter	struct atmio_openvcc op;
14018334Speter	struct ifnet *ifp;
14118334Speter	int error = 0;
14218334Speter	int proto = so->so_proto->pr_protocol;
14318334Speter
14490075Sobrien	npcb = (struct natmpcb *)so->so_pcb;
14590075Sobrien	KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL"));
14690075Sobrien
14718334Speter	/*
14890075Sobrien	 * Validate nam and npcb.
14990075Sobrien	 */
15090075Sobrien	NATM_LOCK();
15190075Sobrien	snatm = (struct sockaddr_natm *)nam;
15290075Sobrien	if (snatm->snatm_len != sizeof(*snatm) ||
15390075Sobrien		(npcb->npcb_flags & NPCB_FREE) == 0) {
15490075Sobrien		NATM_UNLOCK();
15590075Sobrien		return (EINVAL);
15690075Sobrien	}
15790075Sobrien	if (snatm->snatm_family != AF_NATM) {
15890075Sobrien		NATM_UNLOCK();
15918334Speter		return (EAFNOSUPPORT);
16018334Speter	}
16118334Speter
16218334Speter	snatm->snatm_if[IFNAMSIZ - 1] = '\0';	/* XXX ensure null termination
16318334Speter						   since ifunit() uses strcmp */
16418334Speter
16518334Speter	/*
16618334Speter	 * Convert interface string to ifp, validate.
16718334Speter	 */
16818334Speter	ifp = ifunit(snatm->snatm_if);
16918334Speter	if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
17018334Speter		NATM_UNLOCK();
17118334Speter		return (ENXIO);
17218334Speter	}
17318334Speter	if (ifp->if_output != atm_output) {
17418334Speter		NATM_UNLOCK();
17518334Speter		return (EAFNOSUPPORT);
17618334Speter	}
17718334Speter
17818334Speter	/*
17918334Speter	 * Register us with the NATM PCB layer.
18018334Speter	 */
18118334Speter	if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
18218334Speter		NATM_UNLOCK();
18390075Sobrien		return (EADDRINUSE);
18418334Speter	}
18518334Speter
18618334Speter	/*
18718334Speter	 * Open the channel.
18818334Speter	 *
18918334Speter	 * XXXRW: Eventually desirable to hold mutex over ioctl?
19018334Speter	 */
19118334Speter	bzero(&op, sizeof(op));
19218334Speter	op.rxhand = npcb;
19318334Speter	op.param.flags = ATMIO_FLAG_PVC;
194117395Skan	op.param.vpi = npcb->npcb_vpi;
19518334Speter	op.param.vci = npcb->npcb_vci;
19618334Speter	op.param.rmtu = op.param.tmtu = ifp->if_mtu;
19718334Speter	op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0;
19818334Speter	op.param.traffic = ATMIO_TRAFFIC_UBR;
19918334Speter	NATM_UNLOCK();
20018334Speter
20118334Speter	IFF_LOCKGIANT(ifp);
20218334Speter	if (ifp->if_ioctl == NULL ||
20318334Speter	    ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) {
20418334Speter		IFF_UNLOCKGIANT(ifp);
20518334Speter		return (EIO);
20618334Speter	}
20790075Sobrien	IFF_UNLOCKGIANT(ifp);
20818334Speter	soisconnected(so);
20918334Speter	return (error);
21090075Sobrien}
21118334Speter
21290075Sobrienstatic int
21390075Sobriennatm_usr_disconnect(struct socket *so)
21418334Speter{
21590075Sobrien	struct natmpcb *npcb;
21690075Sobrien	struct atmio_closevcc cl;
21790075Sobrien	struct ifnet *ifp;
21890075Sobrien	int error = 0;
21918334Speter
22018334Speter	npcb = (struct natmpcb *)so->so_pcb;
22118334Speter	KASSERT(npcb != NULL, ("natm_usr_disconnect: npcb == NULL"));
22218334Speter
22390075Sobrien	NATM_LOCK();
22490075Sobrien	if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
22518334Speter		NATM_UNLOCK();
22618334Speter		printf("natm: disconnected check\n");
22718334Speter		return (EIO);
22818334Speter	}
22918334Speter	ifp = npcb->npcb_ifp;
23090075Sobrien
23190075Sobrien	/*
23290075Sobrien	 * Disable rx.
23390075Sobrien	 *
23418334Speter	 * XXXRW: Eventually desirable to hold mutex over ioctl?
23518334Speter	 */
23618334Speter	cl.vpi = npcb->npcb_vpi;
23718334Speter	cl.vci = npcb->npcb_vci;
23818334Speter	NATM_UNLOCK();
23918334Speter	if (ifp->if_ioctl != NULL) {
24018334Speter		IFF_LOCKGIANT(ifp);
24118334Speter		ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl);
24218334Speter		IFF_UNLOCKGIANT(ifp);
24318334Speter	}
24490075Sobrien	soisdisconnected(so);
24590075Sobrien	return (error);
24690075Sobrien}
24718334Speter
24818334Speterstatic int
24918334Speternatm_usr_shutdown(struct socket *so)
25018334Speter{
25118334Speter
25218334Speter	socantsendmore(so);
25318334Speter	return (0);
25418334Speter}
25590075Sobrien
25618334Speterstatic int
25718334Speternatm_usr_send(struct socket *so, int flags, struct mbuf *m,
25818334Speter	struct sockaddr *nam, struct mbuf *control, d_thread_t *p)
25918334Speter{
26018334Speter	struct natmpcb *npcb;
26118334Speter	struct atm_pseudohdr *aph;
26290075Sobrien	int error = 0;
26318334Speter	int proto = so->so_proto->pr_protocol;
26418334Speter
26518334Speter	npcb = (struct natmpcb *)so->so_pcb;
26618334Speter	KASSERT(npcb != NULL, ("natm_usr_send: npcb == NULL"));
26718334Speter
26818334Speter	NATM_LOCK();
26918334Speter	if (control && control->m_len) {
27090075Sobrien		NATM_UNLOCK();
27118334Speter		m_freem(control);
27218334Speter		m_freem(m);
27318334Speter		return (EINVAL);
27418334Speter	}
27518334Speter
27618334Speter	/*
27718334Speter	 * Send the data.  We must put an atm_pseudohdr on first.
27818334Speter	 */
27918334Speter	M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
28018334Speter	if (m == NULL) {
28118334Speter		NATM_UNLOCK();
28218334Speter		m_freem(control);
28318334Speter		return (ENOBUFS);
28490075Sobrien	}
28590075Sobrien	aph = mtod(m, struct atm_pseudohdr *);
28618334Speter	ATM_PH_VPI(aph) = npcb->npcb_vpi;
28718334Speter	ATM_PH_SETVCI(aph, npcb->npcb_vci);
28818334Speter	ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
28918334Speter	error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
29018334Speter	NATM_UNLOCK();
29118334Speter	return (error);
29218334Speter}
29318334Speter
29418334Speterstatic int
29518334Speternatm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
29618334Speter{
29718334Speter	struct natmpcb *npcb;
29818334Speter	struct sockaddr_natm *snatm, ssnatm;
29990075Sobrien
30018334Speter	npcb = (struct natmpcb *)so->so_pcb;
30118334Speter	KASSERT(npcb != NULL, ("natm_usr_peeraddr: npcb == NULL"));
30218334Speter
30318334Speter	NATM_LOCK();
30418334Speter	snatm = &ssnatm;
30518334Speter	bzero(snatm, sizeof(*snatm));
30618334Speter	snatm->snatm_len = sizeof(*snatm);
30718334Speter	snatm->snatm_family = AF_NATM;
30818334Speter	strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
30918334Speter	    sizeof(snatm->snatm_if));
310117395Skan	snatm->snatm_vci = npcb->npcb_vci;
311117395Skan	snatm->snatm_vpi = npcb->npcb_vpi;
31218334Speter	NATM_UNLOCK();
31318334Speter	*nam = sodupsockaddr((struct sockaddr *)snatm, M_WAITOK);
314117395Skan	return (0);
31518334Speter}
316117395Skan
317117395Skanstatic int
318117395Skannatm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
319117395Skan	struct ifnet *ifp, d_thread_t *p)
320117395Skan{
321117395Skan	struct natmpcb *npcb;
32218334Speter	int error;
32318334Speter
32418334Speter	npcb = (struct natmpcb *)so->so_pcb;
32518334Speter	KASSERT(npcb != NULL, ("natm_usr_control: npcb == NULL"));
32618334Speter
32718334Speter	if (ifp == NULL || ifp->if_ioctl == NULL)
32818334Speter		return (EOPNOTSUPP);
32918334Speter	IFF_LOCKGIANT(ifp);
33018334Speter	error = ((*ifp->if_ioctl)(ifp, cmd, arg));
33118334Speter	IFF_UNLOCKGIANT(ifp);
33218334Speter	return (error);
33318334Speter}
33418334Speter
33518334Speterstatic void
33618334Speternatm_usr_abort(struct socket *so)
33718334Speter{
33818334Speter
33918334Speter}
34018334Speter
34118334Speterstatic void
34218334Speternatm_usr_close(struct socket *so)
34318334Speter{
34418334Speter
34518334Speter}
34618334Speter
34718334Speterstatic int
34818334Speternatm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p)
34918334Speter{
35018334Speter
35118334Speter	return (EOPNOTSUPP);
35218334Speter}
35318334Speter
35418334Speterstatic int
35518334Speternatm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
35618334Speter{
35718334Speter
358117395Skan	return (EOPNOTSUPP);
359117395Skan}
360117395Skan
361117395Skan/* xxx - should be const */
362117395Skanstruct pr_usrreqs natm_usrreqs = {
363117395Skan	.pru_abort =		natm_usr_abort,
364117395Skan	.pru_attach =		natm_usr_attach,
365117395Skan	.pru_bind =		natm_usr_bind,
366117395Skan	.pru_connect =		natm_usr_connect,
367117395Skan	.pru_control =		natm_usr_control,
368117395Skan	.pru_detach =		natm_usr_detach,
369117395Skan	.pru_disconnect =	natm_usr_disconnect,
370117395Skan	.pru_peeraddr =		natm_usr_peeraddr,
371117395Skan	.pru_send =		natm_usr_send,
372117395Skan	.pru_shutdown =		natm_usr_shutdown,
373117395Skan	.pru_sockaddr =		natm_usr_sockaddr,
374117395Skan	.pru_close =		natm_usr_close,
375117395Skan};
376117395Skan
377117395Skan/*
378117395Skan * natmintr: interrupt
379117395Skan *
380117395Skan * Note: we expect a socket pointer in rcvif rather than an interface
381117395Skan * pointer.  We can get the interface pointer from the so's PCB if we really
382117395Skan * need it.
383117395Skan */
384117395Skanvoid
385117395Skannatmintr(struct mbuf *m)
386117395Skan{
387117395Skan	struct socket *so;
388117395Skan	struct natmpcb *npcb;
389117395Skan
390117395Skan#ifdef DIAGNOSTIC
391117395Skan	M_ASSERTPKTHDR(m);
392117395Skan#endif
393117395Skan
394117395Skan	NATM_LOCK();
395117395Skan	npcb = (struct natmpcb *)m->m_pkthdr.rcvif;	/* XXX: overloaded */
396117395Skan	so = npcb->npcb_socket;
397117395Skan
398117395Skan	npcb->npcb_inq--;
399117395Skan
400117395Skan	if (npcb->npcb_flags & NPCB_DRAIN) {
401117395Skan		if (npcb->npcb_inq == 0)
402117395Skan			FREE(npcb, M_PCB);			/* done! */
403117395Skan		NATM_UNLOCK();
404117395Skan		m_freem(m);
405117395Skan		return;
406117395Skan	}
407117395Skan
408117395Skan	if (npcb->npcb_flags & NPCB_FREE) {
409117395Skan		NATM_UNLOCK();
410117395Skan		m_freem(m);					/* drop */
411117395Skan		return;
412117395Skan	}
413117395Skan
414117395Skan#ifdef NEED_TO_RESTORE_IFP
415117395Skan	m->m_pkthdr.rcvif = npcb->npcb_ifp;
416117395Skan#else
417117395Skan#ifdef DIAGNOSTIC
418117395Skan	m->m_pkthdr.rcvif = NULL;	/* null it out to be safe */
419117395Skan#endif
420117395Skan#endif
421117395Skan
422117395Skan	if (sbspace(&so->so_rcv) > m->m_pkthdr.len) {
423117395Skan#ifdef NATM_STAT
424117395Skan		natm_sookcnt++;
425117395Skan		natm_sookbytes += m->m_pkthdr.len;
426117395Skan#endif
427117395Skan		sbappendrecord(&so->so_rcv, m);
428117395Skan		sorwakeup(so);
429117395Skan		NATM_UNLOCK();
430117395Skan	} else {
431117395Skan#ifdef NATM_STAT
432117395Skan		natm_sodropcnt++;
433117395Skan		natm_sodropbytes += m->m_pkthdr.len;
434117395Skan#endif
435117395Skan		NATM_UNLOCK();
436117395Skan		m_freem(m);
437117395Skan	}
438117395Skan}
439117395Skan
440117395Skan/*
441117395Skan * natm0_sysctl: not used, but here in case we want to add something
442117395Skan * later...
443117395Skan */
444117395Skanint
445117395Skannatm0_sysctl(SYSCTL_HANDLER_ARGS)
446117395Skan{
447117395Skan
44818334Speter	/* All sysctl names at this level are terminal. */
449117395Skan	return (ENOENT);
450117395Skan}
451117395Skan
452117395Skan/*
453117395Skan * natm5_sysctl: not used, but here in case we want to add something
454117395Skan * later...
45518334Speter */
45618334Speterint
45718334Speternatm5_sysctl(SYSCTL_HANDLER_ARGS)
45818334Speter{
45918334Speter
46018334Speter	/* All sysctl names at this level are terminal. */
46118334Speter	return (ENOENT);
46218334Speter}
46318334Speter