aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c395
1 files changed, 212 insertions, 183 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 9202b2fc7118..4e6c64675358 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
- * $Id: ip_output.c,v 1.79 1998/07/13 12:12:25 bde Exp $
+ * $Id: ip_output.c,v 1.80 1998/08/01 08:44:33 peter Exp $
*/
#define _IP_VHL
@@ -72,6 +72,10 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
#undef COMPAT_IPFW
#endif
+#ifdef COMPAT_IPFW
+#include <netinet/ip_fw.h>
+#endif
+
#ifdef IPFIREWALL_FORWARD_DEBUG
#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
(ntohl(a.s_addr)>>16)&0xFF,\
@@ -85,10 +89,10 @@ static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
static void ip_mloopback
__P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
static int ip_getmoptions
- __P((int, struct ip_moptions *, struct mbuf **));
-static int ip_pcbopts __P((struct mbuf **, struct mbuf *));
+ __P((struct sockopt *, struct ip_moptions *));
+static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *));
static int ip_setmoptions
- __P((int, struct ip_moptions **, struct mbuf *));
+ __P((struct sockopt *, struct ip_moptions **));
#if defined(IPFILTER_LKM) || defined(IPFILTER)
int ip_optcopy __P((struct ip *, struct ip *));
@@ -742,33 +746,43 @@ ip_optcopy(ip, jp)
* IP socket option processing.
*/
int
-ip_ctloutput(op, so, level, optname, mp, p)
- int op;
+ip_ctloutput(so, sopt)
struct socket *so;
- int level, optname;
- struct mbuf **mp;
- struct proc *p;
+ struct sockopt *sopt;
{
- register struct inpcb *inp = sotoinpcb(so);
- register struct mbuf *m = *mp;
- register int optval = 0;
- int error = 0;
+ struct inpcb *inp = sotoinpcb(so);
+ int error, optval;
- if (level != IPPROTO_IP) {
- error = EINVAL;
- if (op == PRCO_SETOPT && *mp)
- (void) m_free(*mp);
- } else switch (op) {
+ error = optval = 0;
+ if (sopt->sopt_level != IPPROTO_IP) {
+ return (EINVAL);
+ }
- case PRCO_SETOPT:
- switch (optname) {
+ switch (sopt->sopt_dir) {
+ case SOPT_SET:
+ switch (sopt->sopt_name) {
case IP_OPTIONS:
#ifdef notyet
case IP_RETOPTS:
- return (ip_pcbopts(optname, &inp->inp_options, m));
-#else
- return (ip_pcbopts(&inp->inp_options, m));
#endif
+ {
+ struct mbuf *m;
+ if (sopt->sopt_valsize > MLEN) {
+ error = EMSGSIZE;
+ break;
+ }
+ MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ error = ENOBUFS;
+ break;
+ }
+ m->m_len = sopt->sopt_valsize;
+ error = sooptcopyin(sopt, mtod(m, char *), m->m_len,
+ m->m_len);
+
+ return (ip_pcbopts(sopt->sopt_name, &inp->inp_options,
+ m));
+ }
case IP_TOS:
case IP_TTL:
@@ -776,41 +790,40 @@ ip_ctloutput(op, so, level, optname, mp, p)
case IP_RECVRETOPTS:
case IP_RECVDSTADDR:
case IP_RECVIF:
- if (m == 0 || m->m_len != sizeof(int))
- error = EINVAL;
- else {
- optval = *mtod(m, int *);
- switch (optname) {
+ error = sooptcopyin(sopt, &optval, sizeof optval,
+ sizeof optval);
+ if (error)
+ break;
- case IP_TOS:
- inp->inp_ip_tos = optval;
- break;
+ switch (sopt->sopt_name) {
+ case IP_TOS:
+ inp->inp_ip_tos = optval;
+ break;
- case IP_TTL:
- inp->inp_ip_ttl = optval;
- break;
+ case IP_TTL:
+ inp->inp_ip_ttl = optval;
+ break;
#define OPTSET(bit) \
if (optval) \
inp->inp_flags |= bit; \
else \
inp->inp_flags &= ~bit;
- case IP_RECVOPTS:
- OPTSET(INP_RECVOPTS);
- break;
+ case IP_RECVOPTS:
+ OPTSET(INP_RECVOPTS);
+ break;
- case IP_RECVRETOPTS:
- OPTSET(INP_RECVRETOPTS);
- break;
+ case IP_RECVRETOPTS:
+ OPTSET(INP_RECVRETOPTS);
+ break;
- case IP_RECVDSTADDR:
- OPTSET(INP_RECVDSTADDR);
- break;
+ case IP_RECVDSTADDR:
+ OPTSET(INP_RECVDSTADDR);
+ break;
- case IP_RECVIF:
- OPTSET(INP_RECVIF);
- break;
- }
+ case IP_RECVIF:
+ OPTSET(INP_RECVIF);
+ break;
}
break;
#undef OPTSET
@@ -821,36 +834,34 @@ ip_ctloutput(op, so, level, optname, mp, p)
case IP_MULTICAST_LOOP:
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
- error = ip_setmoptions(optname, &inp->inp_moptions, m);
+ error = ip_setmoptions(sopt, &inp->inp_moptions);
break;
case IP_PORTRANGE:
- if (m == 0 || m->m_len != sizeof(int))
- error = EINVAL;
- else {
- optval = *mtod(m, int *);
-
- switch (optval) {
+ error = sooptcopyin(sopt, &optval, sizeof optval,
+ sizeof optval);
+ if (error)
+ break;
- case IP_PORTRANGE_DEFAULT:
- inp->inp_flags &= ~(INP_LOWPORT);
- inp->inp_flags &= ~(INP_HIGHPORT);
- break;
+ switch (optval) {
+ case IP_PORTRANGE_DEFAULT:
+ inp->inp_flags &= ~(INP_LOWPORT);
+ inp->inp_flags &= ~(INP_HIGHPORT);
+ break;
- case IP_PORTRANGE_HIGH:
- inp->inp_flags &= ~(INP_LOWPORT);
- inp->inp_flags |= INP_HIGHPORT;
- break;
+ case IP_PORTRANGE_HIGH:
+ inp->inp_flags &= ~(INP_LOWPORT);
+ inp->inp_flags |= INP_HIGHPORT;
+ break;
- case IP_PORTRANGE_LOW:
- inp->inp_flags &= ~(INP_HIGHPORT);
- inp->inp_flags |= INP_LOWPORT;
- break;
+ case IP_PORTRANGE_LOW:
+ inp->inp_flags &= ~(INP_HIGHPORT);
+ inp->inp_flags |= INP_LOWPORT;
+ break;
- default:
- error = EINVAL;
- break;
- }
+ default:
+ error = EINVAL;
+ break;
}
break;
@@ -858,21 +869,19 @@ ip_ctloutput(op, so, level, optname, mp, p)
error = ENOPROTOOPT;
break;
}
- if (m)
- (void)m_free(m);
break;
- case PRCO_GETOPT:
- switch (optname) {
+ case SOPT_GET:
+ switch (sopt->sopt_name) {
case IP_OPTIONS:
case IP_RETOPTS:
- *mp = m = m_get(M_WAIT, MT_SOOPTS);
- if (inp->inp_options) {
- m->m_len = inp->inp_options->m_len;
- bcopy(mtod(inp->inp_options, void *),
- mtod(m, void *), m->m_len);
- } else
- m->m_len = 0;
+ if (inp->inp_options)
+ error = sooptcopyout(sopt,
+ mtod(inp->inp_options,
+ char *),
+ inp->inp_options->m_len);
+ else
+ sopt->sopt_valsize = 0;
break;
case IP_TOS:
@@ -881,9 +890,8 @@ ip_ctloutput(op, so, level, optname, mp, p)
case IP_RECVRETOPTS:
case IP_RECVDSTADDR:
case IP_RECVIF:
- *mp = m = m_get(M_WAIT, MT_SOOPTS);
- m->m_len = sizeof(int);
- switch (optname) {
+ case IP_PORTRANGE:
+ switch (sopt->sopt_name) {
case IP_TOS:
optval = inp->inp_ip_tos;
@@ -910,8 +918,17 @@ ip_ctloutput(op, so, level, optname, mp, p)
case IP_RECVIF:
optval = OPTBIT(INP_RECVIF);
break;
+
+ case IP_PORTRANGE:
+ if (inp->inp_flags & INP_HIGHPORT)
+ optval = IP_PORTRANGE_HIGH;
+ else if (inp->inp_flags & INP_LOWPORT)
+ optval = IP_PORTRANGE_LOW;
+ else
+ optval = 0;
+ break;
}
- *mtod(m, int *) = optval;
+ error = sooptcopyout(sopt, &optval, sizeof optval);
break;
case IP_MULTICAST_IF:
@@ -920,21 +937,7 @@ ip_ctloutput(op, so, level, optname, mp, p)
case IP_MULTICAST_LOOP:
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
- error = ip_getmoptions(optname, inp->inp_moptions, mp);
- break;
-
- case IP_PORTRANGE:
- *mp = m = m_get(M_WAIT, MT_SOOPTS);
- m->m_len = sizeof(int);
-
- if (inp->inp_flags & INP_HIGHPORT)
- optval = IP_PORTRANGE_HIGH;
- else if (inp->inp_flags & INP_LOWPORT)
- optval = IP_PORTRANGE_LOW;
- else
- optval = 0;
-
- *mtod(m, int *) = optval;
+ error = ip_getmoptions(sopt, inp->inp_moptions);
break;
default:
@@ -952,12 +955,8 @@ ip_ctloutput(op, so, level, optname, mp, p)
* with destination address if source routed.
*/
static int
-#ifdef notyet
ip_pcbopts(optname, pcbopt, m)
int optname;
-#else
-ip_pcbopts(pcbopt, m)
-#endif
struct mbuf **pcbopt;
register struct mbuf *m;
{
@@ -1054,23 +1053,28 @@ bad:
}
/*
+ * XXX
+ * The whole multicast option thing needs to be re-thought.
+ * Several of these options are equally applicable to non-multicast
+ * transmission, and one (IP_MULTICAST_TTL) totally duplicates a
+ * standard option (IP_TTL).
+ */
+/*
* Set the IP multicast options in response to user setsockopt().
*/
static int
-ip_setmoptions(optname, imop, m)
- int optname;
+ip_setmoptions(sopt, imop)
+ struct sockopt *sopt;
struct ip_moptions **imop;
- struct mbuf *m;
{
- register int error = 0;
- u_char loop;
- register int i;
+ int error = 0;
+ int i;
struct in_addr addr;
- register struct ip_mreq *mreq;
- register struct ifnet *ifp;
- register struct ip_moptions *imo = *imop;
+ struct ip_mreq mreq;
+ struct ifnet *ifp;
+ struct ip_moptions *imo = *imop;
struct route ro;
- register struct sockaddr_in *dst;
+ struct sockaddr_in *dst;
int s;
if (imo == NULL) {
@@ -1091,18 +1095,16 @@ ip_setmoptions(optname, imop, m)
imo->imo_num_memberships = 0;
}
- switch (optname) {
+ switch (sopt->sopt_name) {
/* store an index number for the vif you wanna use in the send */
case IP_MULTICAST_VIF:
- if (!legal_vif_num) {
+ if (legal_vif_num == 0) {
error = EOPNOTSUPP;
break;
}
- if (m == NULL || m->m_len != sizeof(int)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
+ if (error)
break;
- }
- i = *(mtod(m, int *));
if (!legal_vif_num(i) && (i != -1)) {
error = EINVAL;
break;
@@ -1114,11 +1116,9 @@ ip_setmoptions(optname, imop, m)
/*
* Select the interface for outgoing multicast packets.
*/
- if (m == NULL || m->m_len != sizeof(struct in_addr)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr);
+ if (error)
break;
- }
- addr = *(mtod(m, struct in_addr *));
/*
* INADDR_ANY is used to remove a previous selection.
* When no interface is selected, a default one is
@@ -1147,25 +1147,50 @@ ip_setmoptions(optname, imop, m)
case IP_MULTICAST_TTL:
/*
* Set the IP time-to-live for outgoing multicast packets.
+ * The original multicast API required a char argument,
+ * which is inconsistent with the rest of the socket API.
+ * We allow either a char or an int.
*/
- if (m == NULL || m->m_len != 1) {
- error = EINVAL;
- break;
+ if (sopt->sopt_valsize == 1) {
+ u_char ttl;
+ error = sooptcopyin(sopt, &ttl, 1, 1);
+ if (error)
+ break;
+ imo->imo_multicast_ttl = ttl;
+ } else {
+ u_int ttl;
+ error = sooptcopyin(sopt, &ttl, sizeof ttl,
+ sizeof ttl);
+ if (error)
+ break;
+ if (ttl > 255)
+ error = EINVAL;
+ else
+ imo->imo_multicast_ttl = ttl;
}
- imo->imo_multicast_ttl = *(mtod(m, u_char *));
break;
case IP_MULTICAST_LOOP:
/*
* Set the loopback flag for outgoing multicast packets.
- * Must be zero or one.
+ * Must be zero or one. The original multicast API required a
+ * char argument, which is inconsistent with the rest
+ * of the socket API. We allow either a char or an int.
*/
- if (m == NULL || m->m_len != 1 ||
- (loop = *(mtod(m, u_char *))) > 1) {
- error = EINVAL;
- break;
+ if (sopt->sopt_valsize == 1) {
+ u_char loop;
+ error = sooptcopyin(sopt, &loop, 1, 1);
+ if (error)
+ break;
+ imo->imo_multicast_loop = !!loop;
+ } else {
+ u_int loop;
+ error = sooptcopyin(sopt, &loop, sizeof loop,
+ sizeof loop);
+ if (error)
+ break;
+ imo->imo_multicast_loop = !!loop;
}
- imo->imo_multicast_loop = loop;
break;
case IP_ADD_MEMBERSHIP:
@@ -1173,12 +1198,11 @@ ip_setmoptions(optname, imop, m)
* Add a multicast group membership.
* Group must be a valid IP multicast address.
*/
- if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
+ if (error)
break;
- }
- mreq = mtod(m, struct ip_mreq *);
- if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+
+ if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
error = EINVAL;
break;
}
@@ -1187,12 +1211,12 @@ ip_setmoptions(optname, imop, m)
* If no interface address was provided, use the interface of
* the route to the given multicast address.
*/
- if (mreq->imr_interface.s_addr == INADDR_ANY) {
+ if (mreq.imr_interface.s_addr == INADDR_ANY) {
bzero((caddr_t)&ro, sizeof(ro));
dst = (struct sockaddr_in *)&ro.ro_dst;
dst->sin_len = sizeof(*dst);
dst->sin_family = AF_INET;
- dst->sin_addr = mreq->imr_multiaddr;
+ dst->sin_addr = mreq.imr_multiaddr;
rtalloc(&ro);
if (ro.ro_rt == NULL) {
error = EADDRNOTAVAIL;
@@ -1203,7 +1227,7 @@ ip_setmoptions(optname, imop, m)
rtfree(ro.ro_rt);
}
else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ INADDR_TO_IFP(mreq.imr_interface, ifp);
}
/*
@@ -1222,7 +1246,7 @@ ip_setmoptions(optname, imop, m)
for (i = 0; i < imo->imo_num_memberships; ++i) {
if (imo->imo_membership[i]->inm_ifp == ifp &&
imo->imo_membership[i]->inm_addr.s_addr
- == mreq->imr_multiaddr.s_addr)
+ == mreq.imr_multiaddr.s_addr)
break;
}
if (i < imo->imo_num_memberships) {
@@ -1240,7 +1264,7 @@ ip_setmoptions(optname, imop, m)
* address list for the given interface.
*/
if ((imo->imo_membership[i] =
- in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
+ in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) {
error = ENOBUFS;
splx(s);
break;
@@ -1254,12 +1278,11 @@ ip_setmoptions(optname, imop, m)
* Drop a multicast group membership.
* Group must be a valid IP multicast address.
*/
- if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
+ if (error)
break;
- }
- mreq = mtod(m, struct ip_mreq *);
- if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+
+ if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
error = EINVAL;
break;
}
@@ -1269,10 +1292,10 @@ ip_setmoptions(optname, imop, m)
* If an interface address was specified, get a pointer
* to its ifnet structure.
*/
- if (mreq->imr_interface.s_addr == INADDR_ANY)
+ if (mreq.imr_interface.s_addr == INADDR_ANY)
ifp = NULL;
else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ INADDR_TO_IFP(mreq.imr_interface, ifp);
if (ifp == NULL) {
error = EADDRNOTAVAIL;
splx(s);
@@ -1286,7 +1309,7 @@ ip_setmoptions(optname, imop, m)
if ((ifp == NULL ||
imo->imo_membership[i]->inm_ifp == ifp) &&
imo->imo_membership[i]->inm_addr.s_addr ==
- mreq->imr_multiaddr.s_addr)
+ mreq.imr_multiaddr.s_addr)
break;
}
if (i == imo->imo_num_memberships) {
@@ -1332,57 +1355,63 @@ ip_setmoptions(optname, imop, m)
* Return the IP multicast options in response to user getsockopt().
*/
static int
-ip_getmoptions(optname, imo, mp)
- int optname;
+ip_getmoptions(sopt, imo)
+ struct sockopt *sopt;
register struct ip_moptions *imo;
- register struct mbuf **mp;
{
- u_char *ttl;
- u_char *loop;
- struct in_addr *addr;
+ struct in_addr addr;
struct in_ifaddr *ia;
+ int error, optval;
+ u_char coptval;
- *mp = m_get(M_WAIT, MT_SOOPTS);
-
- switch (optname) {
-
+ error = 0;
+ switch (sopt->sopt_name) {
case IP_MULTICAST_VIF:
if (imo != NULL)
- *(mtod(*mp, int *)) = imo->imo_multicast_vif;
+ optval = imo->imo_multicast_vif;
else
- *(mtod(*mp, int *)) = -1;
- (*mp)->m_len = sizeof(int);
- return(0);
+ optval = -1;
+ error = sooptcopyout(sopt, &optval, sizeof optval);
+ break;
case IP_MULTICAST_IF:
- addr = mtod(*mp, struct in_addr *);
- (*mp)->m_len = sizeof(struct in_addr);
if (imo == NULL || imo->imo_multicast_ifp == NULL)
- addr->s_addr = INADDR_ANY;
+ addr.s_addr = INADDR_ANY;
else {
IFP_TO_IA(imo->imo_multicast_ifp, ia);
- addr->s_addr = (ia == NULL) ? INADDR_ANY
- : IA_SIN(ia)->sin_addr.s_addr;
+ addr.s_addr = (ia == NULL) ? INADDR_ANY
+ : IA_SIN(ia)->sin_addr.s_addr;
}
- return (0);
+ error = sooptcopyout(sopt, &addr, sizeof addr);
+ break;
case IP_MULTICAST_TTL:
- ttl = mtod(*mp, u_char *);
- (*mp)->m_len = 1;
- *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
- : imo->imo_multicast_ttl;
- return (0);
+ if (imo == 0)
+ optval = coptval = IP_DEFAULT_MULTICAST_TTL;
+ else
+ optval = coptval = imo->imo_multicast_ttl;
+ if (sopt->sopt_valsize == 1)
+ error = sooptcopyout(sopt, &coptval, 1);
+ else
+ error = sooptcopyout(sopt, &optval, sizeof optval);
+ break;
case IP_MULTICAST_LOOP:
- loop = mtod(*mp, u_char *);
- (*mp)->m_len = 1;
- *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
- : imo->imo_multicast_loop;
- return (0);
+ if (imo == 0)
+ optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
+ else
+ optval = coptval = imo->imo_multicast_loop;
+ if (sopt->sopt_valsize == 1)
+ error = sooptcopyout(sopt, &coptval, 1);
+ else
+ error = sooptcopyout(sopt, &optval, sizeof optval);
+ break;
default:
- return (EOPNOTSUPP);
+ error = ENOPROTOOPT;
+ break;
}
+ return (error);
}
/*