xref: /csrg-svn/sys/net/raw_cb.c (revision 7517)
1*7517Sroot /*	raw_cb.c	4.11	82/07/24	*/
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"
136339Ssam #include "../net/pup.h"
147298Ssam #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
216339Ssam  *	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 
366339Ssam 	if (ifnet == 0)
376339Ssam 		return (EADDRNOTAVAIL);
385635Sroot 	/*
395635Sroot 	 * Should we verify address not already in use?
405635Sroot 	 * Some say yes, others no.
415635Sroot 	 */
425635Sroot 	if (addr) switch (addr->sa_family) {
435635Sroot 
445772Swnj 	case AF_IMPLINK:
456339Ssam 	case AF_INET:
466339Ssam 		if (((struct sockaddr_in *)addr)->sin_addr.s_addr &&
476339Ssam 		    if_ifwithaddr(addr) == 0)
486339Ssam 			return (EADDRNOTAVAIL);
495635Sroot 		break;
505635Sroot 
516339Ssam #ifdef PUP
526339Ssam 	/*
536339Ssam 	 * Curious, we convert PUP address format to internet
546339Ssam 	 * to allow us to verify we're asking for an Ethernet
556339Ssam 	 * interface.  This is wrong, but things are heavily
566339Ssam 	 * oriented towards the internet addressing scheme, and
576339Ssam 	 * converting internet to PUP would be very expensive.
586339Ssam 	 */
596339Ssam 	case AF_PUP: {
606339Ssam 		struct sockaddr_pup *spup = (struct sockaddr_pup *)addr;
616339Ssam 		struct sockaddr_in inpup;
626339Ssam 
636339Ssam 		bzero((caddr_t)&inpup, sizeof(inpup));
646509Ssam 		inpup.sin_family = AF_INET;
656339Ssam 		inpup.sin_addr.s_net = spup->sp_net;
666339Ssam 		inpup.sin_addr.s_impno = spup->sp_host;
676339Ssam 		if (inpup.sin_addr.s_addr &&
686339Ssam 		    if_ifwithaddr((struct sockaddr *)&inpup) == 0)
696339Ssam 			return (EADDRNOTAVAIL);
706045Swnj 		break;
716339Ssam 	}
726339Ssam #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;
896529Ssam 	if (addr) {
906509Ssam 		bcopy((caddr_t)addr, (caddr_t)&rp->rcb_laddr, sizeof(*addr));
916529Ssam 		rp->rcb_flags |= RAW_LADDR;
926529Ssam 	}
935635Sroot 	return (0);
945635Sroot bad2:
955635Sroot 	sbrelease(&so->so_snd);
965635Sroot bad:
975635Sroot 	(void) m_free(m);
985635Sroot 	return (ENOBUFS);
995635Sroot }
1005635Sroot 
1015635Sroot /*
1025635Sroot  * Detach the raw connection block and discard
1035635Sroot  * socket resources.
1045635Sroot  */
1055635Sroot raw_detach(rp)
1065635Sroot 	register struct rawcb *rp;
1075635Sroot {
1085635Sroot 	struct socket *so = rp->rcb_socket;
1095635Sroot 
1105635Sroot 	so->so_pcb = 0;
1115635Sroot 	sofree(so);
1125635Sroot 	remque(rp);
1136339Ssam 	(void) m_freem(dtom(rp));
1145635Sroot }
1155635Sroot 
1165635Sroot /*
1175635Sroot  * Disconnect and possibly release resources.
1185635Sroot  */
1195635Sroot raw_disconnect(rp)
1205635Sroot 	struct rawcb *rp;
1215635Sroot {
1226509Ssam 	rp->rcb_flags &= ~RAW_FADDR;
123*7517Sroot 	if (rp->rcb_socket->so_state & SS_NOFDREF)
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 {
1356509Ssam 	bcopy((caddr_t)addr, (caddr_t)&rp->rcb_faddr, sizeof(*addr));
1366509Ssam 	rp->rcb_flags |= RAW_FADDR;
1375635Sroot }
138