BSD 4_3_Net_1 release
[unix-history] / sys / net / raw_cb.c
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)raw_cb.c 7.7 (Berkeley) 2/17/89
*/
#include "param.h"
#include "systm.h"
#include "mbuf.h"
#include "socket.h"
#include "socketvar.h"
#include "domain.h"
#include "protosw.h"
#include "errno.h"
#include "if.h"
#include "route.h"
#include "raw_cb.h"
#include "../netinet/in.h"
#include "../machine/mtpr.h"
/*
* Routines to manage the raw protocol control blocks.
*
* TODO:
* hash lookups by protocol family/protocol + address family
* take care of unique address problems per AF?
* redo address binding to allow wildcards
*/
u_long raw_sendspace = RAWSNDQ;
u_long raw_recvspace = RAWRCVQ;
/*
* Allocate a control block and a nominal amount
* of buffer space for the socket.
*/
raw_attach(so, proto)
register struct socket *so;
int proto;
{
struct mbuf *m;
register struct rawcb *rp;
m = m_getclr(M_DONTWAIT, MT_PCB);
if (m == 0)
return (ENOBUFS);
if (sbreserve(&so->so_snd, raw_sendspace) == 0)
goto bad;
if (sbreserve(&so->so_rcv, raw_recvspace) == 0)
goto bad2;
rp = mtod(m, struct rawcb *);
rp->rcb_socket = so;
so->so_pcb = (caddr_t)rp;
rp->rcb_pcb = 0;
rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family;
rp->rcb_proto.sp_protocol = proto;
insque(rp, &rawcb);
return (0);
bad2:
sbrelease(&so->so_snd);
bad:
(void) m_free(m);
return (ENOBUFS);
}
/*
* Detach the raw connection block and discard
* socket resources.
*/
raw_detach(rp)
register struct rawcb *rp;
{
struct socket *so = rp->rcb_socket;
if (rp->rcb_route.ro_rt)
rtfree(rp->rcb_route.ro_rt);
so->so_pcb = 0;
sofree(so);
remque(rp);
if (rp->rcb_options)
m_freem(rp->rcb_options);
m_freem(dtom(rp));
}
/*
* Disconnect and possibly release resources.
*/
raw_disconnect(rp)
struct rawcb *rp;
{
rp->rcb_flags &= ~RAW_FADDR;
if (rp->rcb_socket->so_state & SS_NOFDREF)
raw_detach(rp);
}
raw_bind(so, nam)
register struct socket *so;
struct mbuf *nam;
{
struct sockaddr *addr = mtod(nam, struct sockaddr *);
register struct rawcb *rp;
if (ifnet == 0)
return (EADDRNOTAVAIL);
/* BEGIN DUBIOUS */
/*
* Should we verify address not already in use?
* Some say yes, others no.
*/
switch (addr->sa_family) {
#ifdef INET
case AF_IMPLINK:
case AF_INET: {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr &&
ifa_ifwithaddr(addr) == 0)
return (EADDRNOTAVAIL);
break;
}
#endif
default:
return (EAFNOSUPPORT);
}
/* END DUBIOUS */
rp = sotorawcb(so);
bcopy((caddr_t)addr, (caddr_t)&rp->rcb_laddr, sizeof (*addr));
rp->rcb_flags |= RAW_LADDR;
return (0);
}
/*
* Associate a peer's address with a
* raw connection block.
*/
raw_connaddr(rp, nam)
struct rawcb *rp;
struct mbuf *nam;
{
struct sockaddr *addr = mtod(nam, struct sockaddr *);
bcopy((caddr_t)addr, (caddr_t)&rp->rcb_faddr, sizeof(*addr));
rp->rcb_flags |= RAW_FADDR;
}