xref: /csrg-svn/sys/net/raw_cb.c (revision 6339)
1*6339Ssam /*	raw_cb.c	4.6	82/03/28	*/
25635Sroot 
35635Sroot #include "../h/param.h"
45635Sroot #include "../h/systm.h"
55635Sroot #include "../h/mbuf.h"
65635Sroot #include "../h/socket.h"
75635Sroot #include "../h/socketvar.h"
85635Sroot #include "../h/mtpr.h"
95635Sroot #include "../net/in.h"
105635Sroot #include "../net/in_systm.h"
115635Sroot #include "../net/if.h"
125635Sroot #include "../net/raw_cb.h"
13*6339Ssam #include "../net/pup.h"
146045Swnj #include "../errno.h"
155635Sroot 
165635Sroot /*
175635Sroot  * Routines to manage the raw protocol control blocks.
185635Sroot  *
195635Sroot  * TODO:
205635Sroot  *	hash lookups by protocol family/protocol + address family
21*6339Ssam  *	take care of unique address problems per AF?
226045Swnj  *	redo address binding to allow wildcards
235635Sroot  */
245635Sroot 
255635Sroot /*
265635Sroot  * Allocate a control block and a nominal amount
275635Sroot  * of buffer space for the socket.
285635Sroot  */
295635Sroot raw_attach(so, addr)
305635Sroot 	register struct socket *so;
315635Sroot 	struct sockaddr *addr;
325635Sroot {
335635Sroot 	struct mbuf *m;
345635Sroot 	register struct rawcb *rp;
355635Sroot 
365635Sroot COUNT(RAW_ATTACH);
37*6339Ssam 	if (ifnet == 0)
38*6339Ssam 		return (EADDRNOTAVAIL);
395635Sroot 	/*
405635Sroot 	 * Should we verify address not already in use?
415635Sroot 	 * Some say yes, others no.
425635Sroot 	 */
435635Sroot 	if (addr) switch (addr->sa_family) {
445635Sroot 
455772Swnj 	case AF_IMPLINK:
46*6339Ssam 	case AF_INET:
47*6339Ssam 		if (((struct sockaddr_in *)addr)->sin_addr.s_addr &&
48*6339Ssam 		    if_ifwithaddr(addr) == 0)
49*6339Ssam 			return (EADDRNOTAVAIL);
505635Sroot 		break;
515635Sroot 
52*6339Ssam #ifdef PUP
53*6339Ssam 	/*
54*6339Ssam 	 * Curious, we convert PUP address format to internet
55*6339Ssam 	 * to allow us to verify we're asking for an Ethernet
56*6339Ssam 	 * interface.  This is wrong, but things are heavily
57*6339Ssam 	 * oriented towards the internet addressing scheme, and
58*6339Ssam 	 * converting internet to PUP would be very expensive.
59*6339Ssam 	 */
60*6339Ssam 	case AF_PUP: {
61*6339Ssam 		struct sockaddr_pup *spup = (struct sockaddr_pup *)addr;
62*6339Ssam 		struct sockaddr_in inpup;
63*6339Ssam 
64*6339Ssam 		bzero((caddr_t)&inpup, sizeof(inpup));
65*6339Ssam 		inpup.sin_addr.s_net = spup->sp_net;
66*6339Ssam 		inpup.sin_addr.s_impno = spup->sp_host;
67*6339Ssam 		if (inpup.sin_addr.s_addr &&
68*6339Ssam 		    if_ifwithaddr((struct sockaddr *)&inpup) == 0)
69*6339Ssam 			return (EADDRNOTAVAIL);
706045Swnj 		break;
71*6339Ssam 	}
72*6339Ssam #endif
736045Swnj 
745635Sroot 	default:
755635Sroot 		return (EAFNOSUPPORT);
765635Sroot 	}
775635Sroot 	m = m_getclr(M_DONTWAIT);
785635Sroot 	if (m == 0)
795635Sroot 		return (ENOBUFS);
805635Sroot 	if (sbreserve(&so->so_snd, RAWSNDQ) == 0)
815635Sroot 		goto bad;
825635Sroot 	if (sbreserve(&so->so_rcv, RAWRCVQ) == 0)
835635Sroot 		goto bad2;
845635Sroot 	rp = mtod(m, struct rawcb *);
855635Sroot 	rp->rcb_socket = so;
865635Sroot 	insque(rp, &rawcb);
875635Sroot 	so->so_pcb = (caddr_t)rp;
885635Sroot 	rp->rcb_pcb = 0;
895635Sroot 	if (addr)
906161Ssam 		bcopy((caddr_t)addr, (caddr_t)&so->so_addr, sizeof(*addr));
915635Sroot 	return (0);
925635Sroot bad2:
935635Sroot 	sbrelease(&so->so_snd);
945635Sroot bad:
955635Sroot 	(void) m_free(m);
965635Sroot 	return (ENOBUFS);
975635Sroot }
985635Sroot 
995635Sroot /*
1005635Sroot  * Detach the raw connection block and discard
1015635Sroot  * socket resources.
1025635Sroot  */
1035635Sroot raw_detach(rp)
1045635Sroot 	register struct rawcb *rp;
1055635Sroot {
1065635Sroot 	struct socket *so = rp->rcb_socket;
1075635Sroot 
1085635Sroot COUNT(RAW_DETACH);
1095635Sroot 	so->so_pcb = 0;
1105635Sroot 	sofree(so);
1115635Sroot 	remque(rp);
112*6339Ssam 	(void) m_freem(dtom(rp));
1135635Sroot }
1145635Sroot 
1155635Sroot /*
1165635Sroot  * Disconnect and possibly release resources.
1175635Sroot  */
1185635Sroot raw_disconnect(rp)
1195635Sroot 	struct rawcb *rp;
1205635Sroot {
1215635Sroot COUNT(RAW_DISCONNECT);
1225635Sroot 	rp->rcb_flags &= ~RAW_ADDR;
1235635Sroot 	if (rp->rcb_socket->so_state & SS_USERGONE)
1245635Sroot 		raw_detach(rp);
1255635Sroot }
1265635Sroot 
1275635Sroot /*
1285635Sroot  * Associate a peer's address with a
1295635Sroot  * raw connection block.
1305635Sroot  */
1315635Sroot raw_connaddr(rp, addr)
1325635Sroot 	struct rawcb *rp;
1335635Sroot 	struct sockaddr *addr;
1345635Sroot {
1355635Sroot COUNT(RAW_CONNADDR);
136*6339Ssam 	bcopy((caddr_t)addr, (caddr_t)&rp->rcb_addr, sizeof(*addr));
1375635Sroot 	rp->rcb_flags |= RAW_ADDR;
1385635Sroot }
139