-/* $OpenBSD: ip_input.c,v 1.312 2017/06/19 17:58:49 bluhm Exp $ */
+/* $OpenBSD: ip_input.c,v 1.313 2017/06/26 19:06:12 bluhm Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
static struct mbuf_queue ipsend_mq;
-void ip_ours(struct mbuf *);
-void ip_local(struct mbuf *);
+int ip_ours(struct mbuf **, int *, int, int);
+int ip_local(struct mbuf **, int *, int, int);
int ip_dooptions(struct mbuf *, struct ifnet *);
int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **);
* between the network layer (input/forward path) running without
* KERNEL_LOCK() and the transport layer still needing it.
*/
-void
-ip_ours(struct mbuf *m)
+int
+ip_ours(struct mbuf **mp, int *offp, int nxt, int af)
{
- niq_enqueue(&ipintrq, m);
+ niq_enqueue(&ipintrq, *mp);
+ *mp = NULL;
+ return IPPROTO_DONE;
}
/*
ipintr(void)
{
struct mbuf *m;
+ int off, nxt;
while ((m = niq_dequeue(&ipintrq)) != NULL) {
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("ipintr no HDR");
#endif
- ip_local(m);
+ off = 0;
+ nxt = ip_local(&m, &off, IPPROTO_IPV4, AF_UNSPEC);
+ KASSERT(nxt == IPPROTO_DONE);
}
}
void
ipv4_input(struct ifnet *ifp, struct mbuf *m)
{
+ int off, nxt;
+
+ off = 0;
+ nxt = ip_input_if(&m, &off, IPPROTO_IPV4, AF_UNSPEC, ifp);
+ KASSERT(nxt == IPPROTO_DONE);
+}
+
+int
+ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
+{
+ struct mbuf *m = *mp;
struct rtentry *rt = NULL;
struct ip *ip;
int hlen, len;
in_addr_t pfrdr = 0;
+ KASSERT(*offp == 0);
+
ipstat_inc(ips_total);
if (m->m_len < sizeof (struct ip) &&
- (m = m_pullup(m, sizeof (struct ip))) == NULL) {
+ (m = *mp = m_pullup(m, sizeof (struct ip))) == NULL) {
ipstat_inc(ips_toosmall);
- goto out;
+ goto bad;
}
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION) {
goto bad;
}
if (hlen > m->m_len) {
- if ((m = m_pullup(m, hlen)) == NULL) {
+ if ((m = *mp = m_pullup(m, hlen)) == NULL) {
ipstat_inc(ips_badhlen);
- goto out;
+ goto bad;
}
ip = mtod(m, struct ip *);
}
* Packet filter
*/
pfrdr = ip->ip_dst.s_addr;
- if (pf_test(AF_INET, PF_IN, ifp, &m) != PF_PASS)
+ if (pf_test(AF_INET, PF_IN, ifp, mp) != PF_PASS)
goto bad;
+ m = *mp;
if (m == NULL)
- goto out;
+ goto bad;
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
* to be sent and the original packet to be freed).
*/
if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp)) {
- goto out;
+ m = *mp = NULL;
+ goto bad;
}
if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
ip->ip_dst.s_addr == INADDR_ANY) {
- ip_ours(m);
+ nxt = ip_ours(mp, offp, nxt, af);
goto out;
}
if (in_ouraddr(m, ifp, &rt)) {
- ip_ours(m);
+ nxt = ip_ours(mp, offp, nxt, af);
goto out;
}
int error;
if (m->m_flags & M_EXT) {
- if ((m = m_pullup(m, hlen)) == NULL) {
+ if ((m = *mp = m_pullup(m, hlen)) == NULL) {
ipstat_inc(ips_toosmall);
- goto out;
+ goto bad;
}
ip = mtod(m, struct ip *);
}
* host belongs to their destination groups.
*/
if (ip->ip_p == IPPROTO_IGMP) {
- ip_ours(m);
+ nxt = ip_ours(mp, offp, nxt, af);
goto out;
}
ipstat_inc(ips_forward);
ipstat_inc(ips_cantforward);
goto bad;
}
- ip_ours(m);
+ nxt = ip_ours(mp, offp, nxt, af);
goto out;
}
#endif /* IPSEC */
ip_forward(m, ifp, rt, pfrdr);
- return;
-bad:
- m_freem(m);
-out:
+ *mp = NULL;
+ return IPPROTO_DONE;
+ bad:
+ nxt = IPPROTO_DONE;
+ m_freemp(mp);
+ out:
rtfree(rt);
+ return nxt;
}
/*
*
* If fragmented try to reassemble. Pass to next level.
*/
-void
-ip_local(struct mbuf *m)
+int
+ip_local(struct mbuf **mp, int *offp, int nxt, int af)
{
+ struct mbuf *m = *mp;
struct ip *ip = mtod(m, struct ip *);
struct ipq *fp;
struct ipqent *ipqe;
*/
if (ip->ip_off &~ htons(IP_DF | IP_RF)) {
if (m->m_flags & M_EXT) { /* XXX */
- if ((m = m_pullup(m, hlen)) == NULL) {
+ if ((m = *mp = m_pullup(m, hlen)) == NULL) {
ipstat_inc(ips_toosmall);
- return;
+ goto bad;
}
ip = mtod(m, struct ip *);
}
ipqe->ipqe_mff = mff;
ipqe->ipqe_m = m;
ipqe->ipqe_ip = ip;
- m = ip_reass(ipqe, fp);
- if (m == NULL) {
- return;
- }
+ m = *mp = ip_reass(ipqe, fp);
+ if (m == NULL)
+ goto bad;
ipstat_inc(ips_reassembled);
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
ip_freef(fp);
}
- ip_deliver(&m, &hlen, ip->ip_p, AF_INET);
- return;
-bad:
- m_freem(m);
+ *offp = hlen;
+ return ip_deliver(mp, offp, ip->ip_p, AF_INET);
+ bad:
+ m_freemp(mp);
+ return IPPROTO_DONE;
}
-void
+int
ip_deliver(struct mbuf **mp, int *offp, int nxt, int af)
{
KERNEL_ASSERT_LOCKED();
ipstat_inc(ips_delivered);
nxt = (*inetsw[ip_protox[nxt]].pr_input)(mp, offp, nxt, af);
KASSERT(nxt == IPPROTO_DONE);
- return;
+ return nxt;
#ifdef IPSEC
bad:
#endif
m_freemp(mp);
+ return IPPROTO_DONE;
}
int
m_freem(m);
pool_put(&ipqent_pool, ipqe);
ip_frags--;
- return (0);
+ return (NULL);
}
/*