aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
authorGarrett Wollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
committerGarrett Wollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
commitcfe8b629f1f13b06fa1aec801248b7e431e48aba (patch)
tree3eeab04394efe1f50741907aeba96200abbaf6d2 /sys/netinet/ip_output.c
parentbdad325c19fcba9b0c6bd42495fa1ae0eda6c2fb (diff)
downloadsrc-cfe8b629f1f13b06fa1aec801248b7e431e48aba.tar.gz
src-cfe8b629f1f13b06fa1aec801248b7e431e48aba.zip
Yow! Completely change the way socket options are handled, eliminating
another specialized mbuf type in the process. Also clean up some of the cruft surrounding IPFW, multicast routing, RSVP, and other ill-explored corners.
Notes
Notes: svn path=/head/; revision=38482
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);
}
/*