Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/raw_ip.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/raw_ip.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.116.2.3 retrieving revision 1.158.2.2 diff -u -p -r1.116.2.3 -r1.158.2.2 --- src/sys/netinet/raw_ip.c 2013/09/23 00:57:53 1.116.2.3 +++ src/sys/netinet/raw_ip.c 2016/11/04 14:49:21 1.158.2.2 @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip.c,v 1.116.2.3 2013/09/23 00:57:53 rmind Exp $ */ +/* $NetBSD: raw_ip.c,v 1.158.2.2 2016/11/04 14:49:21 pgoyette Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -65,12 +65,14 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.116.2.3 2013/09/23 00:57:53 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.158.2.2 2016/11/04 14:49:21 pgoyette Exp $"); +#ifdef _KERNEL_OPT #include "opt_inet.h" #include "opt_compat_netbsd.h" #include "opt_ipsec.h" #include "opt_mrouting.h" +#endif #include #include @@ -78,11 +80,12 @@ __KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1 #include #include #include +#include #include +#include #include #include -#include #include #include @@ -99,15 +102,20 @@ __KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1 #include #include #include -#endif +#endif /* IPSEC */ #ifdef COMPAT_50 #include #endif -static inpcbtable_t * rawcbtable __read_mostly; +struct inpcbtable rawcbtable; + +int rip_pcbnotify(struct inpcbtable *, struct in_addr, + struct in_addr, int, int, void (*)(struct inpcb *, int)); +static int rip_connect_pcb(struct inpcb *, struct sockaddr_in *); +static void rip_disconnect1(struct inpcb *); -static void sysctl_net_inet_raw_setup(struct sysctllog **); +static void sysctl_net_inet_raw_setup(struct sysctllog **); /* * Nominal space allocated to a raw ip socket. @@ -118,104 +126,57 @@ static void sysctl_net_inet_raw_setup(s static u_long rip_sendspace = RIPSNDQ; static u_long rip_recvspace = RIPRCVQ; -struct rip_input_ctx { - struct mbuf * mbuf; - struct ip * ip; - struct sockaddr_in src; - unsigned hlen; - unsigned nfound; -}; - -struct rip_ctlinput_ctx { - struct ip * ip; - struct in_addr addr; - int errno; -}; +/* + * Raw interface to IP protocol. + */ +/* + * Initialize raw connection block q. + */ void rip_init(void) { - rawcbtable = inpcb_init(1, 1, 0); + sysctl_net_inet_raw_setup(NULL); + in_pcbinit(&rawcbtable, 1, 1); } -/* - * rip_append: pass the received datagram to the process. - */ static void -rip_append(inpcb_t *inp, struct rip_input_ctx *rctx) +rip_sbappendaddr(struct inpcb *last, struct ip *ip, const struct sockaddr *sa, + int hlen, struct mbuf *opts, struct mbuf *n) { - struct socket *so = inpcb_get_socket(inp); - int inpflags = inpcb_get_flags(inp); - struct mbuf *n, *opts = NULL; - - /* XXX: Might optimise this, but not with a silly loop! */ - if ((n = m_copypacket(rctx->mbuf, M_DONTWAIT)) == NULL) { - return; - } - - if (inpflags & INP_NOHEADER) { - m_adj(n, rctx->hlen); - } - - if ((inpflags & INP_CONTROLOPTS) != 0 + if (last->inp_flags & INP_NOHEADER) + m_adj(n, hlen); + if (last->inp_flags & INP_CONTROLOPTS #ifdef SO_OTIMESTAMP - || (so->so_options & SO_OTIMESTAMP) != 0 + || last->inp_socket->so_options & SO_OTIMESTAMP #endif - || (so->so_options & SO_TIMESTAMP) != 0) { - struct ip *ip = rctx->ip; - ip_savecontrol(inp, &opts, ip, n); - } - - if (sbappendaddr(&so->so_rcv, sintosa(&rctx->src), n, opts) == 0) { - /* Should notify about lost packet. */ - if (opts) { - m_freem(opts); - } + || last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, n); + if (sbappendaddr(&last->inp_socket->so_rcv, sa, n, opts) == 0) { + /* should notify about lost packet */ m_freem(n); - } else { - sorwakeup(so); - } -} - -static int -rip_pcb_process(inpcb_t *inp, void *arg) -{ - struct rip_input_ctx *rctx = arg; - const struct ip *ip = rctx->ip; - struct ip *inp_ip = in_getiphdr(inp); - struct in_addr laddr, faddr; - - if (inp_ip->ip_p && inp_ip->ip_p != ip->ip_p) { - return 0; - } - inpcb_get_addrs(inp, &laddr, &faddr); - - if (!in_nullhost(laddr) && !in_hosteq(laddr, ip->ip_dst)) { - return 0; - } - if (!in_nullhost(faddr) && !in_hosteq(faddr, ip->ip_src)) { - return 0; - } - -#if defined(IPSEC) - /* Check AH/ESP integrity. */ - if (ipsec4_in_reject_so(rctx->mbuf, inpcb_get_socket(inp))) { - /* Do not inject data into PCB. */ - IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); - return 0; - } -#endif - rip_append(inp, rctx); - rctx->nfound++; - return 0; + if (opts) + m_freem(opts); + } else + sorwakeup(last->inp_socket); } +/* + * Setup generic address and protocol structures + * for raw_input routine, then pass them along with + * mbuf chain. + */ void rip_input(struct mbuf *m, ...) { + int hlen, proto; struct ip *ip = mtod(m, struct ip *); - int error, hlen, proto; + struct inpcb_hdr *inph; + struct inpcb *inp; + struct inpcb *last = NULL; + struct mbuf *n, *opts = NULL; + struct sockaddr_in ripsrc; va_list ap; va_start(ap, m); @@ -223,68 +184,102 @@ rip_input(struct mbuf *m, ...) proto = va_arg(ap, int); va_end(ap); - KASSERTMSG((proto == ip->ip_p), "%s: protocol mismatch", __func__); + sockaddr_in_init(&ripsrc, &ip->ip_src, 0); /* - * Compatibility: programs using raw IP expect ip_len field to have - * the header length subtracted. Also, ip_len and ip_off fields are - * expected to be in host order. + * XXX Compatibility: programs using raw IP expect ip_len + * XXX to have the header length subtracted, and in host order. + * XXX ip_off is also expected to be host order. */ hlen = ip->ip_hl << 2; ip->ip_len = ntohs(ip->ip_len) - hlen; NTOHS(ip->ip_off); - /* Save some context for the iterator. */ - struct rip_input_ctx rctx = { - .mbuf = m, .ip = ip, .hlen = hlen, .nfound = 0 - }; - sockaddr_in_init(&rctx.src, &ip->ip_src, 0); - - /* Scan all raw IP PCBs for matching entries. */ - error = inpcb_foreach(rawcbtable, AF_INET, rip_pcb_process, &rctx); - KASSERT(error == 0); - - /* Done, if found any. */ - if (rctx.nfound) { - return; + TAILQ_FOREACH(inph, &rawcbtable.inpt_queue, inph_queue) { + inp = (struct inpcb *)inph; + if (inp->inp_af != AF_INET) + continue; + if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) + continue; + if (!in_nullhost(inp->inp_laddr) && + !in_hosteq(inp->inp_laddr, ip->ip_dst)) + continue; + if (!in_nullhost(inp->inp_faddr) && + !in_hosteq(inp->inp_faddr, ip->ip_src)) + continue; + if (last == NULL) + ; +#if defined(IPSEC) + /* check AH/ESP integrity. */ + else if (ipsec_used && + ipsec4_in_reject_so(m, last->inp_socket)) { + IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); + /* do not inject data to pcb */ + } +#endif /*IPSEC*/ + else if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) { + rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, + n); + opts = NULL; + } + last = inp; } - - if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { +#if defined(IPSEC) + /* check AH/ESP integrity. */ + if (ipsec_used && last != NULL + && ipsec4_in_reject_so(m, last->inp_socket)) { + m_freem(m); + IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); + IP_STATDEC(IP_STAT_DELIVERED); + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ + if (last != NULL) + rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, m); + else if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { uint64_t *ips; - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, + 0, 0); ips = IP_STAT_GETREF(); ips[IP_STAT_NOPROTO]++; ips[IP_STAT_DELIVERED]--; IP_STAT_PUTREF(); - } else { + } else m_freem(m); - } + return; } -static int -rip_pcbnotify(inpcb_t *inp, void *arg) -{ - struct rip_ctlinput_ctx *rctx = arg; - const struct ip *ip = rctx->ip; - struct ip *inp_ip = in_getiphdr(inp); - struct in_addr laddr, faddr; - - if (inp_ip->ip_p && inp_ip->ip_p != ip->ip_p) { - return 0; +int +rip_pcbnotify(struct inpcbtable *table, + struct in_addr faddr, struct in_addr laddr, int proto, int errno, + void (*notify)(struct inpcb *, int)) +{ + struct inpcb_hdr *inph, *ninph; + int nmatch; + + nmatch = 0; + TAILQ_FOREACH_SAFE(inph, &table->inpt_queue, inph_queue, ninph) { + struct inpcb *inp = (struct inpcb *)inph; + if (inp->inp_af != AF_INET) + continue; + if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) + continue; + if (in_hosteq(inp->inp_faddr, faddr) && + in_hosteq(inp->inp_laddr, laddr)) { + (*notify)(inp, errno); + nmatch++; + } } - inpcb_get_addrs(inp, &laddr, &faddr); - if (in_hosteq(faddr, rctx->addr) && in_hosteq(laddr, ip->ip_src)) { - inpcb_rtchange(inp, rctx->errno); - } - return 0; + return nmatch; } void * rip_ctlinput(int cmd, const struct sockaddr *sa, void *v) { struct ip *ip = v; + void (*notify)(struct inpcb *, int) = in_rtchange; int errno; if (sa->sa_family != AF_INET || @@ -293,118 +288,101 @@ rip_ctlinput(int cmd, const struct socka if ((unsigned)cmd >= PRC_NCMDS) return NULL; errno = inetctlerrmap[cmd]; - - if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD || ip == NULL) { - inpcb_notifyall(rawcbtable, satocsin(sa)->sin_addr, - errno, inpcb_rtchange); + if (PRC_IS_REDIRECT(cmd)) + notify = in_rtchange, ip = 0; + else if (cmd == PRC_HOSTDEAD) + ip = 0; + else if (errno == 0) return NULL; - } else if (errno == 0) { - return NULL; - } - - /* Note: mapped address case. */ - struct rip_ctlinput_ctx rctx = { - .ip = ip, .addr = satocsin(sa)->sin_addr, .errno = errno - }; - (void)inpcb_foreach(rawcbtable, AF_INET, rip_pcbnotify, &rctx); - + if (ip) { + rip_pcbnotify(&rawcbtable, satocsin(sa)->sin_addr, + ip->ip_src, ip->ip_p, errno, notify); + + /* XXX mapped address case */ + } else + in_pcbnotifyall(&rawcbtable, satocsin(sa)->sin_addr, errno, + notify); return NULL; } /* - * Generate IP header and pass packet to the IP output routine. + * Generate IP header and pass packet to ip_output. * Tack on options user may have setup with control call. */ int -rip_output(struct mbuf *m, ...) +rip_output(struct mbuf *m, struct inpcb *inp) { - inpcb_t *inp; - struct socket *so; struct ip *ip; struct mbuf *opts; - int flags, inpflags; - va_list ap; + int flags; - va_start(ap, m); - inp = va_arg(ap, inpcb_t *); - va_end(ap); - - so = inpcb_get_socket(inp); - KASSERT(solocked(so)); - - flags = (so->so_options & SO_DONTROUTE) | - IP_ALLOWBROADCAST | IP_RETURNMTU; - inpflags = inpcb_get_flags(inp); + flags = + (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST + | IP_RETURNMTU; /* * If the user handed us a complete IP packet, use it. * Otherwise, allocate an mbuf for a header and fill it in. */ - if ((inpflags & INP_HDRINCL) == 0) { - struct ip *inp_ip = in_getiphdr(inp); - + if ((inp->inp_flags & INP_HDRINCL) == 0) { if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { m_freem(m); - return EMSGSIZE; + return (EMSGSIZE); } M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); - if (m == NULL) { - return ENOBUFS; - } + if (!m) + return (ENOBUFS); ip = mtod(m, struct ip *); ip->ip_tos = 0; ip->ip_off = htons(0); - ip->ip_p = inp_ip->ip_p; + ip->ip_p = inp->inp_ip.ip_p; ip->ip_len = htons(m->m_pkthdr.len); - inpcb_get_addrs(inp, &ip->ip_src, &ip->ip_dst); - + ip->ip_src = inp->inp_laddr; + ip->ip_dst = inp->inp_faddr; ip->ip_ttl = MAXTTL; - opts = inpcb_get_options(inp); + opts = inp->inp_options; } else { if (m->m_pkthdr.len > IP_MAXPACKET) { m_freem(m); - return EMSGSIZE; + return (EMSGSIZE); } ip = mtod(m, struct ip *); /* - * If the mbuf is read-only, we need to allocate a new mbuf - * for the header, since we need to modify the header. + * If the mbuf is read-only, we need to allocate + * a new mbuf for the header, since we need to + * modify the header. */ if (M_READONLY(m)) { - const int hlen = ip->ip_hl << 2; + int hlen = ip->ip_hl << 2; m = m_copyup(m, hlen, (max_linkhdr + 3) & ~3); - if (m == NULL) { - return ENOMEM; /* XXX */ - } + if (m == NULL) + return (ENOMEM); /* XXX */ ip = mtod(m, struct ip *); } - /* - * Applications on raw sockets pass us packets - * in host byte order. - */ + /* XXX userland passes ip_len and ip_off in host order */ if (m->m_pkthdr.len != ip->ip_len) { m_freem(m); return (EINVAL); } HTONS(ip->ip_len); HTONS(ip->ip_off); - if (ip->ip_id || m->m_pkthdr.len < IP_MINFRAGSIZE) { + if (ip->ip_id != 0 || m->m_pkthdr.len < IP_MINFRAGSIZE) flags |= IP_NOIPNEWID; - } opts = NULL; - - /* - * Note: prevent IP output from overwriting header fields. - */ + /* XXX prevent ip_output from overwriting header fields */ flags |= IP_RAWOUTPUT; IP_STATINC(IP_STAT_RAWOUT); } - return ip_output(m, opts, inpcb_get_route(inp), flags, - inpcb_get_moptions(inp), so); + /* + * IP output. Note: if IP_RETURNMTU flag is set, the MTU size + * will be stored in inp_errormtu. + */ + return ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, + inp->inp_socket); } /* @@ -413,34 +391,30 @@ rip_output(struct mbuf *m, ...) int rip_ctloutput(int op, struct socket *so, struct sockopt *sopt) { - inpcb_t *inp = sotoinpcb(so); - int inpflags = inpcb_get_flags(inp); - int error = 0, optval; - - KASSERT(solocked(so)); + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int optval; if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) { if (op == PRCO_GETOPT) { - optval = (inpflags & INP_NOHEADER) ? 1 : 0; + optval = (inp->inp_flags & INP_NOHEADER) ? 1 : 0; error = sockopt_set(sopt, &optval, sizeof(optval)); } else if (op == PRCO_SETOPT) { error = sockopt_getint(sopt, &optval); if (error) goto out; if (optval) { - inpflags &= ~INP_HDRINCL; - inpflags |= INP_NOHEADER; + inp->inp_flags &= ~INP_HDRINCL; + inp->inp_flags |= INP_NOHEADER; } else - inpflags &= ~INP_NOHEADER; + inp->inp_flags &= ~INP_NOHEADER; } goto out; - } - - if (sopt->sopt_level != IPPROTO_IP) { + } else if (sopt->sopt_level != IPPROTO_IP) return ip_ctloutput(op, so, sopt); - } switch (op) { + case PRCO_SETOPT: switch (sopt->sopt_name) { case IP_HDRINCL: @@ -448,9 +422,9 @@ rip_ctloutput(int op, struct socket *so, if (error) break; if (optval) - inpflags |= INP_HDRINCL; + inp->inp_flags |= INP_HDRINCL; else - inpflags &= ~INP_HDRINCL; + inp->inp_flags &= ~INP_HDRINCL; break; #ifdef MROUTING @@ -477,7 +451,7 @@ rip_ctloutput(int op, struct socket *so, case PRCO_GETOPT: switch (sopt->sopt_name) { case IP_HDRINCL: - optval = inpflags & INP_HDRINCL; + optval = inp->inp_flags & INP_HDRINCL; error = sockopt_set(sopt, &optval, sizeof(optval)); break; @@ -497,57 +471,32 @@ rip_ctloutput(int op, struct socket *so, break; } out: - if (!error) { - inpcb_set_flags(inp, inpflags); - } return error; } -static int -rip_bind(inpcb_t *inp, struct mbuf *nam) -{ - struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); - - if (nam->m_len != sizeof(*addr)) - return EINVAL; - if (!IFNET_FIRST()) - return EADDRNOTAVAIL; - if (addr->sin_family != AF_INET) - return EAFNOSUPPORT; - if (!in_nullhost(addr->sin_addr) && !ifa_ifwithaddr(sintosa(addr))) - return EADDRNOTAVAIL; - - inpcb_set_addrs(inp, &addr->sin_addr, NULL); - return 0; -} - -static int -rip_connect(inpcb_t *inp, struct mbuf *nam) +int +rip_connect_pcb(struct inpcb *inp, struct sockaddr_in *addr) { - struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); - if (nam->m_len != sizeof(*addr)) - return EINVAL; - if (!IFNET_FIRST()) - return EADDRNOTAVAIL; + if (IFNET_READER_EMPTY()) + return (EADDRNOTAVAIL); if (addr->sin_family != AF_INET) - return EAFNOSUPPORT; - - inpcb_set_addrs(inp, NULL, &addr->sin_addr); - return 0; + return (EAFNOSUPPORT); + inp->inp_faddr = addr->sin_addr; + return (0); } static void -rip_disconnect(inpcb_t *inp) +rip_disconnect1(struct inpcb *inp) { - inpcb_set_addrs(inp, NULL, &zeroin_addr); + + inp->inp_faddr = zeroin_addr; } static int rip_attach(struct socket *so, int proto) { - inpcb_t *inp; - struct ip *ip; + struct inpcb *inp; int error; KASSERT(sotoinpcb(so) == NULL); @@ -560,16 +509,13 @@ rip_attach(struct socket *so, int proto) } } - solock(so); - error = inpcb_create(so, rawcbtable); + error = in_pcballoc(so, &rawcbtable); if (error) { - sounlock(so); return error; } inp = sotoinpcb(so); - ip = in_getiphdr(inp); - ip->ip_p = proto; - sounlock(so); + inp->inp_ip.ip_p = proto; + KASSERT(solocked(so)); return 0; } @@ -577,7 +523,7 @@ rip_attach(struct socket *so, int proto) static void rip_detach(struct socket *so) { - inpcb_t *inp; + struct inpcb *inp; KASSERT(solocked(so)); inp = sotoinpcb(so); @@ -589,152 +535,332 @@ rip_detach(struct socket *so) ip_mrouter_done(); } #endif - inpcb_destroy(inp); + in_pcbdetach(inp); } -int -rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, - struct mbuf *control, struct lwp *l) +static int +rip_accept(struct socket *so, struct sockaddr *nam) { - inpcb_t *inp; - int error = 0; + KASSERT(solocked(so)); - KASSERT(req != PRU_ATTACH); - KASSERT(req != PRU_DETACH); + panic("rip_accept"); - if (req == PRU_CONTROL) { - return in_control(so, (long)m, nam, (ifnet_t *)control, l); - } - if (req == PRU_PURGEIF) { - int s = splsoftnet(); - mutex_enter(softnet_lock); - inpcb_purgeif0(rawcbtable, (ifnet_t *)control); - in_purgeif((ifnet_t *)control); - inpcb_purgeif(rawcbtable, (ifnet_t *)control); - mutex_exit(softnet_lock); - splx(s); - return 0; - } + return EOPNOTSUPP; +} + +static int +rip_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) +{ + struct inpcb *inp = sotoinpcb(so); + struct sockaddr_in *addr = (struct sockaddr_in *)nam; + int error = 0; + int s, ss; + struct ifaddr *ifa; KASSERT(solocked(so)); - inp = sotoinpcb(so); + KASSERT(inp != NULL); + KASSERT(nam != NULL); - KASSERT(!control || (req == PRU_SEND || req == PRU_SENDOOB)); - if (inp == NULL) { + if (addr->sin_len != sizeof(*addr)) return EINVAL; + + s = splsoftnet(); + if (IFNET_READER_EMPTY()) { + error = EADDRNOTAVAIL; + goto release; + } + if (addr->sin_family != AF_INET) { + error = EAFNOSUPPORT; + goto release; + } + ss = pserialize_read_enter(); + if ((ifa = ifa_ifwithaddr(sintosa(addr))) == NULL && + !in_nullhost(addr->sin_addr)) + { + pserialize_read_exit(ss); + error = EADDRNOTAVAIL; + goto release; + } + if (ifa && (ifatoia(ifa))->ia4_flags & IN6_IFF_DUPLICATED) { + pserialize_read_exit(ss); + error = EADDRNOTAVAIL; + goto release; } + pserialize_read_exit(ss); - switch (req) { - case PRU_BIND: - error = rip_bind(inp, nam); - break; + inp->inp_laddr = addr->sin_addr; - case PRU_LISTEN: - error = EOPNOTSUPP; - break; +release: + splx(s); + return error; +} - case PRU_CONNECT: - error = rip_connect(inp, nam); - if (error) - break; +static int +rip_listen(struct socket *so, struct lwp *l) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) +{ + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int s; + + KASSERT(solocked(so)); + KASSERT(inp != NULL); + KASSERT(nam != NULL); + + s = splsoftnet(); + error = rip_connect_pcb(inp, (struct sockaddr_in *)nam); + if (! error) soisconnected(so); - break; + splx(s); - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; + return error; +} - case PRU_DISCONNECT: - soisdisconnected(so); - rip_disconnect(inp); - break; +static int +rip_connect2(struct socket *so, struct socket *so2) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip_disconnect(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + int s; + + KASSERT(solocked(so)); + KASSERT(inp != NULL); + + s = splsoftnet(); + soisdisconnected(so); + rip_disconnect1(inp); + splx(s); + + return 0; +} + +static int +rip_shutdown(struct socket *so) +{ + int s; + + KASSERT(solocked(so)); /* * Mark the connection as being incapable of further input. */ - case PRU_SHUTDOWN: - socantsendmore(so); - break; + s = splsoftnet(); + socantsendmore(so); + splx(s); - case PRU_RCVD: - error = EOPNOTSUPP; - break; + return 0; +} + +static int +rip_abort(struct socket *so) +{ + KASSERT(solocked(so)); + + panic("rip_abort"); + + return EOPNOTSUPP; +} + +static int +rip_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) +{ + return in_control(so, cmd, nam, ifp); +} + +static int +rip_stat(struct socket *so, struct stat *ub) +{ + KASSERT(solocked(so)); + + /* stat: don't bother with a blocksize. */ + return 0; +} + +static int +rip_peeraddr(struct socket *so, struct sockaddr *nam) +{ + int s; + + KASSERT(solocked(so)); + KASSERT(sotoinpcb(so) != NULL); + KASSERT(nam != NULL); + + s = splsoftnet(); + in_setpeeraddr(sotoinpcb(so), (struct sockaddr_in *)nam); + splx(s); + + return 0; +} + +static int +rip_sockaddr(struct socket *so, struct sockaddr *nam) +{ + int s; + + KASSERT(solocked(so)); + KASSERT(sotoinpcb(so) != NULL); + KASSERT(nam != NULL); + + s = splsoftnet(); + in_setsockaddr(sotoinpcb(so), (struct sockaddr_in *)nam); + splx(s); + + return 0; +} + +static int +rip_rcvd(struct socket *so, int flags, struct lwp *l) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip_recvoob(struct socket *so, struct mbuf *m, int flags) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, + struct mbuf *control, struct lwp *l) +{ + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int s; + + KASSERT(solocked(so)); + KASSERT(inp != NULL); + KASSERT(m != NULL); /* * Ship a packet out. The appropriate raw output * routine handles any massaging necessary. */ - case PRU_SEND: - if (control && control->m_len) { - m_freem(control); - m_freem(m); - error = EINVAL; - break; - } + if (control && control->m_len) { + m_freem(control); + m_freem(m); + return EINVAL; + } + + s = splsoftnet(); + if (nam) { if ((so->so_state & SS_ISCONNECTED) != 0) { - error = nam ? EISCONN : ENOTCONN; - m_freem(m); - break; + error = EISCONN; + goto die; } - if (nam && (error = rip_connect(inp, nam)) != 0) { + error = rip_connect_pcb(inp, (struct sockaddr_in *)nam); + if (error) { + die: m_freem(m); - break; + splx(s); + return error; } - error = rip_output(m, inp); - if (nam) { - rip_disconnect(inp); + } else { + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + goto die; } - break; + } + error = rip_output(m, inp); + if (nam) + rip_disconnect1(inp); - case PRU_SENSE: - /* - * Stat: do not bother with a blocksize. - */ - return 0; + splx(s); + return error; +} - case PRU_RCVOOB: - error = EOPNOTSUPP; - break; +static int +rip_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) +{ + KASSERT(solocked(so)); - case PRU_SENDOOB: - m_freem(control); - m_freem(m); - error = EOPNOTSUPP; - break; + m_freem(m); + m_freem(control); - case PRU_SOCKADDR: - inpcb_fetch_sockaddr(inp, nam); - break; + return EOPNOTSUPP; +} - case PRU_PEERADDR: - inpcb_fetch_peeraddr(inp, nam); - break; +static int +rip_purgeif(struct socket *so, struct ifnet *ifp) +{ + int s; - default: - KASSERT(false); - } + s = splsoftnet(); + mutex_enter(softnet_lock); + in_pcbpurgeif0(&rawcbtable, ifp); + in_purgeif(ifp); + in_pcbpurgeif(&rawcbtable, ifp); + mutex_exit(softnet_lock); + splx(s); - return error; + return 0; } -PR_WRAP_USRREQ(rip_usrreq) - -#define rip_usrreq rip_usrreq_wrapper +PR_WRAP_USRREQS(rip) +#define rip_attach rip_attach_wrapper +#define rip_detach rip_detach_wrapper +#define rip_accept rip_accept_wrapper +#define rip_bind rip_bind_wrapper +#define rip_listen rip_listen_wrapper +#define rip_connect rip_connect_wrapper +#define rip_connect2 rip_connect2_wrapper +#define rip_disconnect rip_disconnect_wrapper +#define rip_shutdown rip_shutdown_wrapper +#define rip_abort rip_abort_wrapper +#define rip_ioctl rip_ioctl_wrapper +#define rip_stat rip_stat_wrapper +#define rip_peeraddr rip_peeraddr_wrapper +#define rip_sockaddr rip_sockaddr_wrapper +#define rip_rcvd rip_rcvd_wrapper +#define rip_recvoob rip_recvoob_wrapper +#define rip_send rip_send_wrapper +#define rip_sendoob rip_sendoob_wrapper +#define rip_purgeif rip_purgeif_wrapper const struct pr_usrreqs rip_usrreqs = { .pr_attach = rip_attach, .pr_detach = rip_detach, - .pr_generic = rip_usrreq, + .pr_accept = rip_accept, + .pr_bind = rip_bind, + .pr_listen = rip_listen, + .pr_connect = rip_connect, + .pr_connect2 = rip_connect2, + .pr_disconnect = rip_disconnect, + .pr_shutdown = rip_shutdown, + .pr_abort = rip_abort, + .pr_ioctl = rip_ioctl, + .pr_stat = rip_stat, + .pr_peeraddr = rip_peeraddr, + .pr_sockaddr = rip_sockaddr, + .pr_rcvd = rip_rcvd, + .pr_recvoob = rip_recvoob, + .pr_send = rip_send, + .pr_sendoob = rip_sendoob, + .pr_purgeif = rip_purgeif, }; static void sysctl_net_inet_raw_setup(struct sysctllog **clog) { - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT, - CTLTYPE_NODE, "net", NULL, - NULL, 0, NULL, 0, - CTL_NET, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT, CTLTYPE_NODE, "inet", NULL, @@ -746,11 +872,12 @@ sysctl_net_inet_raw_setup(struct sysctll SYSCTL_DESCR("Raw IPv4 settings"), NULL, 0, NULL, 0, CTL_NET, PF_INET, IPPROTO_RAW, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT, CTLTYPE_STRUCT, "pcblist", SYSCTL_DESCR("Raw IPv4 control block list"), - sysctl_inpcblist, 0, rawcbtable, 0, + sysctl_inpcblist, 0, &rawcbtable, 0, CTL_NET, PF_INET, IPPROTO_RAW, CTL_CREATE, CTL_EOL); }