diff options
author | Jordan K. Hubbard <jkh@FreeBSD.org> | 1996-10-17 18:42:33 +0000 |
---|---|---|
committer | Jordan K. Hubbard <jkh@FreeBSD.org> | 1996-10-17 18:42:33 +0000 |
commit | 04d59a46c0c8496d8fbc9740d186c5fd85b88308 (patch) | |
tree | 1b83462872ff55f51ed7439f97fec9076ac9e96a /sys/netns | |
parent | 102b3fa4c8bc36546cf54c2eff09cb3daed72558 (diff) | |
download | src-test2-04d59a46c0c8496d8fbc9740d186c5fd85b88308.tar.gz src-test2-04d59a46c0c8496d8fbc9740d186c5fd85b88308.zip |
Notes
Diffstat (limited to 'sys/netns')
-rw-r--r-- | sys/netns/idp_usrreq.c | 568 | ||||
-rw-r--r-- | sys/netns/idp_var.h | 55 | ||||
-rw-r--r-- | sys/netns/ns.c | 370 | ||||
-rw-r--r-- | sys/netns/ns.h | 157 | ||||
-rw-r--r-- | sys/netns/ns_cksum.c | 205 | ||||
-rw-r--r-- | sys/netns/ns_error.c | 324 | ||||
-rw-r--r-- | sys/netns/ns_error.h | 96 | ||||
-rw-r--r-- | sys/netns/ns_if.h | 89 | ||||
-rw-r--r-- | sys/netns/ns_input.c | 490 | ||||
-rw-r--r-- | sys/netns/ns_ip.c | 441 | ||||
-rw-r--r-- | sys/netns/ns_output.c | 161 | ||||
-rw-r--r-- | sys/netns/ns_pcb.c | 364 | ||||
-rw-r--r-- | sys/netns/ns_pcb.h | 86 | ||||
-rw-r--r-- | sys/netns/ns_proto.c | 99 | ||||
-rw-r--r-- | sys/netns/sp.h | 58 | ||||
-rw-r--r-- | sys/netns/spidp.h | 68 | ||||
-rw-r--r-- | sys/netns/spp_debug.c | 171 | ||||
-rw-r--r-- | sys/netns/spp_debug.h | 65 | ||||
-rw-r--r-- | sys/netns/spp_timer.h | 128 | ||||
-rw-r--r-- | sys/netns/spp_usrreq.c | 1805 | ||||
-rw-r--r-- | sys/netns/spp_var.h | 221 |
21 files changed, 6021 insertions, 0 deletions
diff --git a/sys/netns/idp_usrreq.c b/sys/netns/idp_usrreq.c new file mode 100644 index 000000000000..592da22aa09a --- /dev/null +++ b/sys/netns/idp_usrreq.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)idp_usrreq.c 8.1 (Berkeley) 6/10/93 + * $Id: idp_usrreq.c,v 1.4 1995/05/30 08:12:20 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netns/ns.h> +#include <netns/ns_pcb.h> +#include <netns/ns_if.h> +#include <netns/idp.h> +#include <netns/idp_var.h> +#include <netns/ns_error.h> + +/* + * IDP protocol implementation. + */ + +struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS }; + +/* + * This may also be called for raw listeners. + */ +idp_input(m, nsp) + struct mbuf *m; + register struct nspcb *nsp; +{ + register struct idp *idp = mtod(m, struct idp *); + struct ifnet *ifp = m->m_pkthdr.rcvif; + + if (nsp==0) + panic("No nspcb"); + /* + * Construct sockaddr format source address. + * Stuff source address and datagram in user buffer. + */ + idp_ns.sns_addr = idp->idp_sna; + if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { + register struct ifaddr *ifa; + + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_NS) { + idp_ns.sns_addr.x_net = + IA_SNS(ifa)->sns_addr.x_net; + break; + } + } + } + nsp->nsp_rpt = idp->idp_pt; + if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { + m->m_len -= sizeof (struct idp); + m->m_pkthdr.len -= sizeof (struct idp); + m->m_data += sizeof (struct idp); + } + if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, + m, (struct mbuf *)0) == 0) + goto bad; + sorwakeup(nsp->nsp_socket); + return; +bad: + m_freem(m); +} + +idp_abort(nsp) + struct nspcb *nsp; +{ + struct socket *so = nsp->nsp_socket; + + ns_pcbdisconnect(nsp); + soisdisconnected(so); +} +/* + * Drop connection, reporting + * the specified error. + */ +struct nspcb * +idp_drop(nsp, errno) + register struct nspcb *nsp; + int errno; +{ + struct socket *so = nsp->nsp_socket; + + /* + * someday, in the xerox world + * we will generate error protocol packets + * announcing that the socket has gone away. + */ + /*if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void) tcp_output(tp); + }*/ + so->so_error = errno; + ns_pcbdisconnect(nsp); + soisdisconnected(so); +} + +int noIdpRoute; +idp_output(nsp, m0) + struct nspcb *nsp; + struct mbuf *m0; +{ + register struct mbuf *m; + register struct idp *idp; + register struct socket *so; + register int len = 0; + register struct route *ro; + struct mbuf *mprev; + extern int idpcksum; + + /* + * Calculate data length. + */ + for (m = m0; m; m = m->m_next) { + mprev = m; + len += m->m_len; + } + /* + * Make sure packet is actually of even length. + */ + + if (len & 1) { + m = mprev; + if ((m->m_flags & M_EXT) == 0 && + (m->m_len + m->m_data < &m->m_dat[MLEN])) { + m->m_len++; + } else { + struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); + + if (m1 == 0) { + m_freem(m0); + return (ENOBUFS); + } + m1->m_len = 1; + * mtod(m1, char *) = 0; + m->m_next = m1; + } + m0->m_pkthdr.len++; + } + + /* + * Fill in mbuf with extended IDP header + * and addresses and length put into network format. + */ + m = m0; + if (nsp->nsp_flags & NSP_RAWOUT) { + idp = mtod(m, struct idp *); + } else { + M_PREPEND(m, sizeof (struct idp), M_DONTWAIT); + if (m == 0) + return (ENOBUFS); + idp = mtod(m, struct idp *); + idp->idp_tc = 0; + idp->idp_pt = nsp->nsp_dpt; + idp->idp_sna = nsp->nsp_laddr; + idp->idp_dna = nsp->nsp_faddr; + len += sizeof (struct idp); + } + + idp->idp_len = htons((u_short)len); + + if (idpcksum) { + idp->idp_sum = 0; + len = ((len - 1) | 1) + 1; + idp->idp_sum = ns_cksum(m, len); + } else + idp->idp_sum = 0xffff; + + /* + * Output datagram. + */ + so = nsp->nsp_socket; + if (so->so_options & SO_DONTROUTE) + return (ns_output(m, (struct route *)0, + (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); + /* + * Use cached route for previous datagram if + * possible. If the previous net was the same + * and the interface was a broadcast medium, or + * if the previous destination was identical, + * then we are ok. + * + * NB: We don't handle broadcasts because that + * would require 3 subroutine calls. + */ + ro = &nsp->nsp_route; +#ifdef ancient_history + /* + * I think that this will all be handled in ns_pcbconnect! + */ + if (ro->ro_rt) { + if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { + /* + * This assumes we have no GH type routes + */ + if (ro->ro_rt->rt_flags & RTF_HOST) { + if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) + goto re_route; + + } + if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { + register struct ns_addr *dst = + &satons_addr(ro->ro_dst); + dst->x_host = idp->idp_dna.x_host; + } + /* + * Otherwise, we go through the same gateway + * and dst is already set up. + */ + } else { + re_route: + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + } + nsp->nsp_lastdst = idp->idp_dna; +#endif /* ancient_history */ + if (noIdpRoute) ro = 0; + return (ns_output(m, ro, so->so_options & SO_BROADCAST)); +} +/* ARGSUSED */ +idp_ctloutput(req, so, level, name, value) + int req, level; + struct socket *so; + int name; + struct mbuf **value; +{ + register struct mbuf *m; + struct nspcb *nsp = sotonspcb(so); + int mask, error = 0; + extern long ns_pexseq; + + if (nsp == NULL) + return (EINVAL); + + switch (req) { + + case PRCO_GETOPT: + if (value==NULL) + return (EINVAL); + m = m_get(M_DONTWAIT, MT_DATA); + if (m==NULL) + return (ENOBUFS); + switch (name) { + + case SO_ALL_PACKETS: + mask = NSP_ALL_PACKETS; + goto get_flags; + + case SO_HEADERS_ON_INPUT: + mask = NSP_RAWIN; + goto get_flags; + + case SO_HEADERS_ON_OUTPUT: + mask = NSP_RAWOUT; + get_flags: + m->m_len = sizeof(short); + *mtod(m, short *) = nsp->nsp_flags & mask; + break; + + case SO_DEFAULT_HEADERS: + m->m_len = sizeof(struct idp); + { + register struct idp *idp = mtod(m, struct idp *); + idp->idp_len = 0; + idp->idp_sum = 0; + idp->idp_tc = 0; + idp->idp_pt = nsp->nsp_dpt; + idp->idp_dna = nsp->nsp_faddr; + idp->idp_sna = nsp->nsp_laddr; + } + break; + + case SO_SEQNO: + m->m_len = sizeof(long); + *mtod(m, long *) = ns_pexseq++; + break; + + default: + error = EINVAL; + } + *value = m; + break; + + case PRCO_SETOPT: + switch (name) { + int *ok; + + case SO_ALL_PACKETS: + mask = NSP_ALL_PACKETS; + goto set_head; + + case SO_HEADERS_ON_INPUT: + mask = NSP_RAWIN; + goto set_head; + + case SO_HEADERS_ON_OUTPUT: + mask = NSP_RAWOUT; + set_head: + if (value && *value) { + ok = mtod(*value, int *); + if (*ok) + nsp->nsp_flags |= mask; + else + nsp->nsp_flags &= ~mask; + } else error = EINVAL; + break; + + case SO_DEFAULT_HEADERS: + { + register struct idp *idp + = mtod(*value, struct idp *); + nsp->nsp_dpt = idp->idp_pt; + } + break; +#ifdef NSIP + + case SO_NSIP_ROUTE: + error = nsip_route(*value); + break; +#endif /* NSIP */ + default: + error = EINVAL; + } + if (value && *value) + m_freem(*value); + break; + } + return (error); +} + +/*ARGSUSED*/ +idp_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + struct nspcb *nsp = sotonspcb(so); + int error = 0; + + if (req == PRU_CONTROL) + return (ns_control(so, (int)m, (caddr_t)nam, + (struct ifnet *)control)); + if (control && control->m_len) { + error = EINVAL; + goto release; + } + if (nsp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + switch (req) { + + case PRU_ATTACH: + if (nsp != NULL) { + error = EINVAL; + break; + } + error = ns_pcballoc(so, &nspcb); + if (error) + break; + error = soreserve(so, (u_long) 2048, (u_long) 2048); + if (error) + break; + break; + + case PRU_DETACH: + if (nsp == NULL) { + error = ENOTCONN; + break; + } + ns_pcbdetach(nsp); + break; + + case PRU_BIND: + error = ns_pcbbind(nsp, nam); + break; + + case PRU_LISTEN: + error = EOPNOTSUPP; + break; + + case PRU_CONNECT: + if (!ns_nullhost(nsp->nsp_faddr)) { + error = EISCONN; + break; + } + error = ns_pcbconnect(nsp, nam); + if (error == 0) + soisconnected(so); + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + case PRU_ACCEPT: + error = EOPNOTSUPP; + break; + + case PRU_DISCONNECT: + if (ns_nullhost(nsp->nsp_faddr)) { + error = ENOTCONN; + break; + } + ns_pcbdisconnect(nsp); + soisdisconnected(so); + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + { + struct ns_addr laddr; + int s; + + if (nam) { + laddr = nsp->nsp_laddr; + if (!ns_nullhost(nsp->nsp_faddr)) { + error = EISCONN; + break; + } + /* + * Must block input while temporarily connected. + */ + s = splnet(); + error = ns_pcbconnect(nsp, nam); + if (error) { + splx(s); + break; + } + } else { + if (ns_nullhost(nsp->nsp_faddr)) { + error = ENOTCONN; + break; + } + } + error = idp_output(nsp, m); + m = NULL; + if (nam) { + ns_pcbdisconnect(nsp); + splx(s); + nsp->nsp_laddr.x_host = laddr.x_host; + nsp->nsp_laddr.x_port = laddr.x_port; + } + } + break; + + case PRU_ABORT: + ns_pcbdetach(nsp); + sofree(so); + soisdisconnected(so); + break; + + case PRU_SOCKADDR: + ns_setsockaddr(nsp, nam); + break; + + case PRU_PEERADDR: + ns_setpeeraddr(nsp, nam); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_CONTROL: + case PRU_RCVD: + case PRU_RCVOOB: + return (EOPNOTSUPP); /* do not free mbuf's */ + + default: + panic("idp_usrreq"); + } +release: + if (control != NULL) + m_freem(control); + if (m != NULL) + m_freem(m); + return (error); +} +/*ARGSUSED*/ +idp_raw_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + int error = 0; + struct nspcb *nsp = sotonspcb(so); + extern struct nspcb nsrawpcb; + + switch (req) { + + case PRU_ATTACH: + + if (!(so->so_state & SS_PRIV) || (nsp != NULL)) { + error = EINVAL; + break; + } + error = ns_pcballoc(so, &nsrawpcb); + if (error) + break; + error = soreserve(so, (u_long) 2048, (u_long) 2048); + if (error) + break; + nsp = sotonspcb(so); + nsp->nsp_faddr.x_host = ns_broadhost; + nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; + break; + default: + error = idp_usrreq(so, req, m, nam, control); + } + return (error); +} + diff --git a/sys/netns/idp_var.h b/sys/netns/idp_var.h new file mode 100644 index 000000000000..e4b9e9f45934 --- /dev/null +++ b/sys/netns/idp_var.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)idp_var.h 8.1 (Berkeley) 6/10/93 + * $Id: idp_var.h,v 1.3 1994/08/21 06:22:06 paul Exp $ + */ + +#ifndef _NETNS_IDP_VAR_H_ +#define _NETNS_IDP_VAR_H_ + +/* + * IDP Kernel Structures and Variables + */ +struct idpstat { + int idps_badsum; /* checksum bad */ + int idps_tooshort; /* packet too short */ + int idps_toosmall; /* not enough data */ + int idps_badhlen; /* ip header length < data size */ + int idps_badlen; /* ip length < ip header length */ +}; + +#ifdef KERNEL +struct idpstat idpstat; +#endif + +#endif diff --git a/sys/netns/ns.c b/sys/netns/ns.c new file mode 100644 index 000000000000..402f6b711bea --- /dev/null +++ b/sys/netns/ns.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns.c 8.2 (Berkeley) 11/15/93 + * $Id: ns.c,v 1.4 1995/05/30 08:12:21 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netns/ns.h> +#include <netns/ns_if.h> + +#ifdef NS + +struct ns_ifaddr *ns_ifaddr; +int ns_interfaces; +extern struct sockaddr_ns ns_netmask, ns_hostmask; + +/* + * Generic internet control operations (ioctl's). + */ +/* ARGSUSED */ +ns_control(so, cmd, data, ifp) + struct socket *so; + int cmd; + caddr_t data; + register struct ifnet *ifp; +{ + register struct ifreq *ifr = (struct ifreq *)data; + register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data; + register struct ns_ifaddr *ia; + struct ifaddr *ifa; + struct ns_ifaddr *oia; + int error, dstIsNew, hostIsNew; + + /* + * Find address for this interface, if it exists. + */ + if (ifp == 0) + return (EADDRNOTAVAIL); + for (ia = ns_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + + switch (cmd) { + + case SIOCGIFADDR: + if (ia == (struct ns_ifaddr *)0) + return (EADDRNOTAVAIL); + *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr; + return (0); + + + case SIOCGIFBRDADDR: + if (ia == (struct ns_ifaddr *)0) + return (EADDRNOTAVAIL); + if ((ifp->if_flags & IFF_BROADCAST) == 0) + return (EINVAL); + *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr; + return (0); + + case SIOCGIFDSTADDR: + if (ia == (struct ns_ifaddr *)0) + return (EADDRNOTAVAIL); + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr; + return (0); + } + + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); + + switch (cmd) { + case SIOCAIFADDR: + case SIOCDIFADDR: + if (ifra->ifra_addr.sns_family == AF_NS) + for (oia = ia; ia; ia = ia->ia_next) { + if (ia->ia_ifp == ifp && + ns_neteq(ia->ia_addr.sns_addr, + ifra->ifra_addr.sns_addr)) + break; + } + if (cmd == SIOCDIFADDR && ia == 0) + return (EADDRNOTAVAIL); + /* FALLTHROUGH */ + + case SIOCSIFADDR: + case SIOCSIFDSTADDR: + if (ia == (struct ns_ifaddr *)0) { + oia = (struct ns_ifaddr *) + malloc(sizeof *ia, M_IFADDR, M_WAITOK); + if (oia == (struct ns_ifaddr *)NULL) + return (ENOBUFS); + bzero((caddr_t)oia, sizeof(*oia)); + if (ia = ns_ifaddr) { + for ( ; ia->ia_next; ia = ia->ia_next) + ; + ia->ia_next = oia; + } else + ns_ifaddr = oia; + ia = oia; + if (ifa = ifp->if_addrlist) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next) + ; + ifa->ifa_next = (struct ifaddr *) ia; + } else + ifp->if_addrlist = (struct ifaddr *) ia; + ia->ia_ifp = ifp; + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + + ia->ia_ifa.ifa_netmask = + (struct sockaddr *)&ns_netmask; + + ia->ia_ifa.ifa_dstaddr = + (struct sockaddr *)&ia->ia_dstaddr; + if (ifp->if_flags & IFF_BROADCAST) { + ia->ia_broadaddr.sns_family = AF_NS; + ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr); + ia->ia_broadaddr.sns_addr.x_host = ns_broadhost; + } + ns_interfaces++; + } + } + + switch (cmd) { + int error; + + case SIOCSIFDSTADDR: + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + if (ia->ia_flags & IFA_ROUTE) { + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + ia->ia_flags &= ~IFA_ROUTE; + } + if (ifp->if_ioctl) { + error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); + if (error) + return (error); + } + *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; + return (0); + + case SIOCSIFADDR: + return (ns_ifinit(ifp, ia, + (struct sockaddr_ns *)&ifr->ifr_addr, 1)); + + case SIOCDIFADDR: + ns_ifscrub(ifp, ia); + if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) + ifp->if_addrlist = ifa->ifa_next; + else { + while (ifa->ifa_next && + (ifa->ifa_next != (struct ifaddr *)ia)) + ifa = ifa->ifa_next; + if (ifa->ifa_next) + ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; + else + printf("Couldn't unlink nsifaddr from ifp\n"); + } + oia = ia; + if (oia == (ia = ns_ifaddr)) { + ns_ifaddr = ia->ia_next; + } else { + while (ia->ia_next && (ia->ia_next != oia)) { + ia = ia->ia_next; + } + if (ia->ia_next) + ia->ia_next = oia->ia_next; + else + printf("Didn't unlink nsifadr from list\n"); + } + IFAFREE((&oia->ia_ifa)); + if (0 == --ns_interfaces) { + /* + * We reset to virginity and start all over again + */ + ns_thishost = ns_zerohost; + } + return (0); + + case SIOCAIFADDR: + dstIsNew = 0; hostIsNew = 1; + if (ia->ia_addr.sns_family == AF_NS) { + if (ifra->ifra_addr.sns_len == 0) { + ifra->ifra_addr = ia->ia_addr; + hostIsNew = 0; + } else if (ns_neteq(ifra->ifra_addr.sns_addr, + ia->ia_addr.sns_addr)) + hostIsNew = 0; + } + if ((ifp->if_flags & IFF_POINTOPOINT) && + (ifra->ifra_dstaddr.sns_family == AF_NS)) { + if (hostIsNew == 0) + ns_ifscrub(ifp, ia); + ia->ia_dstaddr = ifra->ifra_dstaddr; + dstIsNew = 1; + } + if (ifra->ifra_addr.sns_family == AF_NS && + (hostIsNew || dstIsNew)) + error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0); + return (error); + + default: + if (ifp->if_ioctl == 0) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); + } +} + +/* +* Delete any previous route for an old address. +*/ +ns_ifscrub(ifp, ia) + register struct ifnet *ifp; + register struct ns_ifaddr *ia; +{ + if (ia->ia_flags & IFA_ROUTE) { + if (ifp->if_flags & IFF_POINTOPOINT) { + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + } else + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); + ia->ia_flags &= ~IFA_ROUTE; + } +} +/* + * Initialize an interface's internet address + * and routing table entry. + */ +ns_ifinit(ifp, ia, sns, scrub) + register struct ifnet *ifp; + register struct ns_ifaddr *ia; + register struct sockaddr_ns *sns; +{ + struct sockaddr_ns oldaddr; + register union ns_host *h = &ia->ia_addr.sns_addr.x_host; + int s = splimp(), error; + + /* + * Set up new addresses. + */ + oldaddr = ia->ia_addr; + ia->ia_addr = *sns; + /* + * The convention we shall adopt for naming is that + * a supplied address of zero means that "we don't care". + * if there is a single interface, use the address of that + * interface as our 6 byte host address. + * if there are multiple interfaces, use any address already + * used. + * + * Give the interface a chance to initialize + * if this is its first address, + * and to validate the address if necessary. + */ + if (ns_hosteqnh(ns_thishost, ns_zerohost)) { + if (ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { + ia->ia_addr = oldaddr; + splx(s); + return (error); + } + ns_thishost = *h; + } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) + || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { + *h = ns_thishost; + if (ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { + ia->ia_addr = oldaddr; + splx(s); + return (error); + } + if (!ns_hosteqnh(ns_thishost,*h)) { + ia->ia_addr = oldaddr; + splx(s); + return (EINVAL); + } + } else { + ia->ia_addr = oldaddr; + splx(s); + return (EINVAL); + } + ia->ia_ifa.ifa_metric = ifp->if_metric; + /* + * Add route for the network. + */ + if (scrub) { + ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; + ns_ifscrub(ifp, ia); + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + } + if (ifp->if_flags & IFF_POINTOPOINT) + rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); + else { + ia->ia_broadaddr.sns_addr.x_net = ia->ia_addr.sns_addr.x_net; + rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); + } + ia->ia_flags |= IFA_ROUTE; + return (0); +} + +/* + * Return address info for specified internet network. + */ +struct ns_ifaddr * +ns_iaonnetof(dst) + register struct ns_addr *dst; +{ + register struct ns_ifaddr *ia; + register struct ns_addr *compare; + register struct ifnet *ifp; + struct ns_ifaddr *ia_maybe = 0; + union ns_net net = dst->x_net; + + for (ia = ns_ifaddr; ia; ia = ia->ia_next) { + if (ifp = ia->ia_ifp) { + if (ifp->if_flags & IFF_POINTOPOINT) { + compare = &satons_addr(ia->ia_dstaddr); + if (ns_hosteq(*dst, *compare)) + return (ia); + if (ns_neteqnn(net, ia->ia_addr.sns_addr.x_net)) + ia_maybe = ia; + } else { + if (ns_neteqnn(net, ia->ia_addr.sns_addr.x_net)) + return (ia); + } + } + } + return (ia_maybe); +} +#endif diff --git a/sys/netns/ns.h b/sys/netns/ns.h new file mode 100644 index 000000000000..27ba198fbfa6 --- /dev/null +++ b/sys/netns/ns.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns.h 8.1 (Berkeley) 6/10/93 + * $Id: ns.h,v 1.3 1994/08/21 06:22:07 paul Exp $ + */ + +#ifndef _NETNS_NS_H_ +#define _NETNS_NS_H_ + +/* + * Constants and Structures defined by the Xerox Network Software + * per "Internet Transport Protocols", XSIS 028112, December 1981 + */ + +/* + * Protocols + */ +#define NSPROTO_RI 1 /* Routing Information */ +#define NSPROTO_ECHO 2 /* Echo Protocol */ +#define NSPROTO_ERROR 3 /* Error Protocol */ +#define NSPROTO_PE 4 /* Packet Exchange */ +#define NSPROTO_SPP 5 /* Sequenced Packet */ +#define NSPROTO_RAW 255 /* Placemarker*/ +#define NSPROTO_MAX 256 /* Placemarker*/ + + +/* + * Port/Socket numbers: network standard functions + */ + +#define NSPORT_RI 1 /* Routing Information */ +#define NSPORT_ECHO 2 /* Echo */ +#define NSPORT_RE 3 /* Router Error */ + +/* + * Ports < NSPORT_RESERVED are reserved for priveleged + * processes (e.g. root). + */ +#define NSPORT_RESERVED 3000 + +/* flags passed to ns_output as last parameter */ + +#define NS_FORWARDING 0x1 /* most of idp header exists */ +#define NS_ROUTETOIF 0x10 /* same as SO_DONTROUTE */ +#define NS_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ + +#define NS_MAXHOPS 15 + +/* flags passed to get/set socket option */ +#define SO_HEADERS_ON_INPUT 1 +#define SO_HEADERS_ON_OUTPUT 2 +#define SO_DEFAULT_HEADERS 3 +#define SO_LAST_HEADER 4 +#define SO_NSIP_ROUTE 5 +#define SO_SEQNO 6 +#define SO_ALL_PACKETS 7 +#define SO_MTU 8 + + +/* + * NS addressing + */ +union ns_host { + u_char c_host[6]; + u_short s_host[3]; +}; + +union ns_net { + u_char c_net[4]; + u_short s_net[2]; +}; + +union ns_net_u { + union ns_net net_e; + u_long long_e; +}; + +struct ns_addr { + union ns_net x_net; + union ns_host x_host; + u_short x_port; +}; + +/* + * Socket address, Xerox style + */ +struct sockaddr_ns { + u_char sns_len; + u_char sns_family; + struct ns_addr sns_addr; + char sns_zero[2]; +}; +#define sns_port sns_addr.x_port + +#ifdef vax +#define ns_netof(a) (*(long *) & ((a).x_net)) /* XXX - not needed */ +#endif +#define ns_neteqnn(a,b) (((a).s_net[0]==(b).s_net[0]) && \ + ((a).s_net[1]==(b).s_net[1])) +#define ns_neteq(a,b) ns_neteqnn((a).x_net, (b).x_net) +#define satons_addr(sa) (((struct sockaddr_ns *)&(sa))->sns_addr) +#define ns_hosteqnh(s,t) ((s).s_host[0] == (t).s_host[0] && \ + (s).s_host[1] == (t).s_host[1] && (s).s_host[2] == (t).s_host[2]) +#define ns_hosteq(s,t) (ns_hosteqnh((s).x_host,(t).x_host)) +#define ns_nullhost(x) (((x).x_host.s_host[0]==0) && \ + ((x).x_host.s_host[1]==0) && ((x).x_host.s_host[2]==0)) + +#ifdef KERNEL +extern struct domain nsdomain; +union ns_host ns_thishost; +union ns_host ns_zerohost; +union ns_host ns_broadhost; +union ns_net ns_zeronet; +union ns_net ns_broadnet; +u_short ns_cksum(); +#else + +#include <sys/cdefs.h> + +__BEGIN_DECLS +extern struct ns_addr ns_addr __P((const char *)); +extern char *ns_ntoa __P((struct ns_addr)); +__END_DECLS + +#endif + +#endif diff --git a/sys/netns/ns_cksum.c b/sys/netns/ns_cksum.c new file mode 100644 index 000000000000..6bd1bb44742e --- /dev/null +++ b/sys/netns/ns_cksum.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1982, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_cksum.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_cksum.c,v 1.2 1994/08/02 07:51:45 davidg Exp $ + */ + +#include <sys/param.h> +#include <sys/mbuf.h> + +/* + * Checksum routine for Network Systems Protocol Packets (Big-Endian). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + */ + +#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } +#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} + +u_short +ns_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_short *w; + register int sum = 0; + register int mlen = 0; + register int sum2; + + union { + u_short s[2]; + long l; + } l_util; + + for (;m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + /* + * Each trip around loop adds in + * word from one mbuf segment. + */ + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * There is a byte left from the last segment; + * ones-complement add it into the checksum. + */ +#if BYTE_ORDER == BIG_ENDIAN + sum += *(u_char *)w; +#else + sum += *(u_char *)w << 8; +#endif + sum += sum; + w = (u_short *)(1 + (char *)w); + mlen = m->m_len - 1; + len--; + FOLD(sum); + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + /* + * We can do a 16 bit ones complement sum using + * 32 bit arithmetic registers for adding, + * with carries from the low added + * into the high (by normal carry-chaining) + * so long as we fold back before 16 carries have occured. + */ + if (1 & (int) w) + goto uuuuglyy; +#ifndef TINY +/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += sum; sum += w[1]; sum += sum; + sum += w[2]; sum += sum; sum += w[3]; sum += sum; + sum += w[4]; sum += sum; sum += w[5]; sum += sum; + sum += w[6]; sum += sum; sum += w[7]; sum += sum; + FOLD(sum); + sum += w[8]; sum += sum; sum += w[9]; sum += sum; + sum += w[10]; sum += sum; sum += w[11]; sum += sum; + sum += w[12]; sum += sum; sum += w[13]; sum += sum; + sum += w[14]; sum += sum; sum += w[15]; sum += sum; + FOLD(sum); + w += 16; + } + mlen += 32; +#endif + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += sum; sum += w[1]; sum += sum; + sum += w[2]; sum += sum; sum += w[3]; sum += sum; + FOLD(sum); + w += 4; + } + mlen += 8; + while ((mlen -= 2) >= 0) { + sum += *w++; sum += sum; + } + goto commoncase; +uuuuglyy: +#if BYTE_ORDER == BIG_ENDIAN +#define ww(n) (((u_char *)w)[n + n + 1]) +#define vv(n) (((u_char *)w)[n + n]) +#else +#if BYTE_ORDER == LITTLE_ENDIAN +#define vv(n) (((u_char *)w)[n + n + 1]) +#define ww(n) (((u_char *)w)[n + n]) +#endif +#endif + sum2 = 0; +#ifndef TINY + while ((mlen -= 32) >= 0) { + sum += ww(0); sum += sum; sum += ww(1); sum += sum; + sum += ww(2); sum += sum; sum += ww(3); sum += sum; + sum += ww(4); sum += sum; sum += ww(5); sum += sum; + sum += ww(6); sum += sum; sum += ww(7); sum += sum; + FOLD(sum); + sum += ww(8); sum += sum; sum += ww(9); sum += sum; + sum += ww(10); sum += sum; sum += ww(11); sum += sum; + sum += ww(12); sum += sum; sum += ww(13); sum += sum; + sum += ww(14); sum += sum; sum += ww(15); sum += sum; + FOLD(sum); + sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; + sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; + sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; + sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; + FOLD(sum2); + sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; + sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; + sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; + sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; + FOLD(sum2); + w += 16; + } + mlen += 32; +#endif + while ((mlen -= 8) >= 0) { + sum += ww(0); sum += sum; sum += ww(1); sum += sum; + sum += ww(2); sum += sum; sum += ww(3); sum += sum; + FOLD(sum); + sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; + sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; + FOLD(sum2); + w += 4; + } + mlen += 8; + while ((mlen -= 2) >= 0) { + sum += ww(0); sum += sum; + sum2 += vv(0); sum2 += sum2; + w++; + } + sum += (sum2 << 8); +commoncase: + if (mlen == -1) { +#if BYTE_ORDER == BIG_ENDIAN + sum += *(u_char *)w << 8; +#else + sum += *(u_char *)w; +#endif + } + FOLD(sum); + } + if (mlen == -1) { + /* We had an odd number of bytes to sum; assume a garbage + byte of zero and clean up */ + sum += sum; + FOLD(sum); + } + /* + * sum has already been kept to low sixteen bits. + * just examine result and exit. + */ + if(sum==0xffff) sum = 0; + return (sum); +} diff --git a/sys/netns/ns_error.c b/sys/netns/ns_error.c new file mode 100644 index 000000000000..7102c8925f4f --- /dev/null +++ b/sys/netns/ns_error.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 1984, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_error.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_error.c,v 1.3 1995/05/30 08:12:22 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/route.h> + +#include <netns/ns.h> +#include <netns/ns_pcb.h> +#include <netns/idp.h> +#include <netns/ns_error.h> + +#ifdef lint +#define NS_ERRPRINTFS 1 +#endif + +#ifdef NS_ERRPRINTFS +/* + * NS_ERR routines: error generation, receive packet processing, and + * routines to turnaround packets back to the originator. + */ +int ns_errprintfs = 0; +#endif + +ns_err_x(c) +{ + register u_short *w, *lim, *base = ns_errstat.ns_es_codes; + u_short x = c; + + /* + * zero is a legit error code, handle specially + */ + if (x == 0) + return (0); + lim = base + NS_ERR_MAX - 1; + for (w = base + 1; w < lim; w++) { + if (*w == 0) + *w = x; + if (*w == x) + break; + } + return (w - base); +} + +/* + * Generate an error packet of type error + * in response to bad packet. + */ + +ns_error(om, type, param) + struct mbuf *om; + int type; +{ + register struct ns_epidp *ep; + struct mbuf *m; + struct idp *nip; + register struct idp *oip = mtod(om, struct idp *); + extern int idpcksum; + + /* + * If this packet was sent to the echo port, + * and nobody was there, just echo it. + * (Yes, this is a wart!) + */ + if (type == NS_ERR_NOSOCK && + oip->idp_dna.x_port == htons(2) && + (type = ns_echo(om))==0) + return; + +#ifdef NS_ERRPRINTFS + if (ns_errprintfs) + printf("ns_err_error(%x, %d, %d)\n", oip, type, param); +#endif + /* + * Don't Generate error packets in response to multicasts. + */ + if (oip->idp_dna.x_host.c_host[0] & 1) + goto freeit; + + ns_errstat.ns_es_error++; + /* + * Make sure that the old IDP packet had 30 bytes of data to return; + * if not, don't bother. Also don't EVER error if the old + * packet protocol was NS_ERR. + */ + if (oip->idp_len < sizeof(struct idp)) { + ns_errstat.ns_es_oldshort++; + goto freeit; + } + if (oip->idp_pt == NSPROTO_ERROR) { + ns_errstat.ns_es_oldns_err++; + goto freeit; + } + + /* + * First, formulate ns_err message + */ + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == NULL) + goto freeit; + m->m_len = sizeof(*ep); + MH_ALIGN(m, m->m_len); + ep = mtod(m, struct ns_epidp *); + if ((u_int)type > NS_ERR_TOO_BIG) + panic("ns_err_error"); + ns_errstat.ns_es_outhist[ns_err_x(type)]++; + ep->ns_ep_errp.ns_err_num = htons((u_short)type); + ep->ns_ep_errp.ns_err_param = htons((u_short)param); + bcopy((caddr_t)oip, (caddr_t)&ep->ns_ep_errp.ns_err_idp, 42); + nip = &ep->ns_ep_idp; + nip->idp_len = sizeof(*ep); + nip->idp_len = htons((u_short)nip->idp_len); + nip->idp_pt = NSPROTO_ERROR; + nip->idp_tc = 0; + nip->idp_dna = oip->idp_sna; + nip->idp_sna = oip->idp_dna; + if (idpcksum) { + nip->idp_sum = 0; + nip->idp_sum = ns_cksum(m, sizeof(*ep)); + } else + nip->idp_sum = 0xffff; + (void) ns_output(m, (struct route *)0, 0); + +freeit: + m_freem(om); +} + +ns_printhost(p) +register struct ns_addr *p; +{ + + printf("<net:%x%x,host:%x%x%x,port:%x>", + p->x_net.s_net[0], + p->x_net.s_net[1], + p->x_host.s_host[0], + p->x_host.s_host[1], + p->x_host.s_host[2], + p->x_port); + +} + +/* + * Process a received NS_ERR message. + */ +ns_err_input(m) + struct mbuf *m; +{ + register struct ns_errp *ep; + register struct ns_epidp *epidp = mtod(m, struct ns_epidp *); + register int i; + int type, code, param; + + /* + * Locate ns_err structure in mbuf, and check + * that not corrupted and of at least minimum length. + */ +#ifdef NS_ERRPRINTFS + if (ns_errprintfs) { + printf("ns_err_input from "); + ns_printhost(&epidp->ns_ep_idp.idp_sna); + printf("len %d\n", ntohs(epidp->ns_ep_idp.idp_len)); + } +#endif + i = sizeof (struct ns_epidp); + if (((m->m_flags & M_EXT) || m->m_len < i) && + (m = m_pullup(m, i)) == 0) { + ns_errstat.ns_es_tooshort++; + return; + } + ep = &(mtod(m, struct ns_epidp *)->ns_ep_errp); + type = ntohs(ep->ns_err_num); + param = ntohs(ep->ns_err_param); + ns_errstat.ns_es_inhist[ns_err_x(type)]++; + +#ifdef NS_ERRPRINTFS + /* + * Message type specific processing. + */ + if (ns_errprintfs) + printf("ns_err_input, type %d param %d\n", type, param); +#endif + if (type >= NS_ERR_TOO_BIG) { + goto badcode; + } + ns_errstat.ns_es_outhist[ns_err_x(type)]++; + switch (type) { + + case NS_ERR_UNREACH_HOST: + code = PRC_UNREACH_NET; + goto deliver; + + case NS_ERR_TOO_OLD: + code = PRC_TIMXCEED_INTRANS; + goto deliver; + + case NS_ERR_TOO_BIG: + code = PRC_MSGSIZE; + goto deliver; + + case NS_ERR_FULLUP: + code = PRC_QUENCH; + goto deliver; + + case NS_ERR_NOSOCK: + code = PRC_UNREACH_PORT; + goto deliver; + + case NS_ERR_UNSPEC_T: + case NS_ERR_BADSUM_T: + case NS_ERR_BADSUM: + case NS_ERR_UNSPEC: + code = PRC_PARAMPROB; + goto deliver; + + deliver: + /* + * Problem with datagram; advise higher level routines. + */ +#ifdef NS_ERRPRINTFS + if (ns_errprintfs) + printf("deliver to protocol %d\n", + ep->ns_err_idp.idp_pt); +#endif + switch(ep->ns_err_idp.idp_pt) { + case NSPROTO_SPP: + spp_ctlinput(code, (caddr_t)ep); + break; + + default: + idp_ctlinput(code, (caddr_t)ep); + } + + goto freeit; + + default: + badcode: + ns_errstat.ns_es_badcode++; + goto freeit; + + } +freeit: + m_freem(m); +} + +#ifdef notdef +u_long +nstime() +{ + int s = splclock(); + u_long t; + + t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; + splx(s); + return (htonl(t)); +} +#endif + +ns_echo(m) +struct mbuf *m; +{ + register struct idp *idp = mtod(m, struct idp *); + register struct echo { + struct idp ec_idp; + u_short ec_op; /* Operation, 1 = request, 2 = reply */ + } *ec = (struct echo *)idp; + struct ns_addr temp; + + if (idp->idp_pt!=NSPROTO_ECHO) return(NS_ERR_NOSOCK); + if (ec->ec_op!=htons(1)) return(NS_ERR_UNSPEC); + + ec->ec_op = htons(2); + + temp = idp->idp_dna; + idp->idp_dna = idp->idp_sna; + idp->idp_sna = temp; + + if (idp->idp_sum != 0xffff) { + idp->idp_sum = 0; + idp->idp_sum = ns_cksum(m, + (int)(((ntohs(idp->idp_len) - 1)|1)+1)); + } + (void) ns_output(m, (struct route *)0, NS_FORWARDING); + return(0); +} diff --git a/sys/netns/ns_error.h b/sys/netns/ns_error.h new file mode 100644 index 000000000000..b5ecdcf4d9ac --- /dev/null +++ b/sys/netns/ns_error.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1984, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_error.h 8.1 (Berkeley) 6/10/93 + * $Id: ns_error.h,v 1.3 1994/08/21 06:22:07 paul Exp $ + */ + +#ifndef _NETNS_NS_ERROR_H_ +#define _NETNS_NS_ERROR_H_ + +/* + * Xerox NS error messages + */ + +struct ns_errp { + u_short ns_err_num; /* Error Number */ + u_short ns_err_param; /* Error Parameter */ + struct idp ns_err_idp; /* Initial segment of offending + packet */ + u_char ns_err_lev2[12]; /* at least this much higher + level protocol */ +}; +struct ns_epidp { + struct idp ns_ep_idp; + struct ns_errp ns_ep_errp; +}; + +#define NS_ERR_UNSPEC 0 /* Unspecified Error detected at dest. */ +#define NS_ERR_BADSUM 1 /* Bad Checksum detected at dest */ +#define NS_ERR_NOSOCK 2 /* Specified socket does not exist at dest*/ +#define NS_ERR_FULLUP 3 /* Dest. refuses packet due to resource lim.*/ +#define NS_ERR_UNSPEC_T 0x200 /* Unspec. Error occured before reaching dest*/ +#define NS_ERR_BADSUM_T 0x201 /* Bad Checksum detected in transit */ +#define NS_ERR_UNREACH_HOST 0x202 /* Dest cannot be reached from here*/ +#define NS_ERR_TOO_OLD 0x203 /* Packet x'd 15 routers without delivery*/ +#define NS_ERR_TOO_BIG 0x204 /* Packet too large to be forwarded through + some intermediate gateway. The error + parameter field contains the max packet + size that can be accommodated */ +#define NS_ERR_MAX 20 + +/* + * Variables related to this implementation + * of the network systems error message protocol. + */ +struct ns_errstat { +/* statistics related to ns_err packets generated */ + int ns_es_error; /* # of calls to ns_error */ + int ns_es_oldshort; /* no error 'cuz old ip too short */ + int ns_es_oldns_err; /* no error 'cuz old was ns_err */ + int ns_es_outhist[NS_ERR_MAX]; +/* statistics related to input messages processed */ + int ns_es_badcode; /* ns_err_code out of range */ + int ns_es_tooshort; /* packet < IDP_MINLEN */ + int ns_es_checksum; /* bad checksum */ + int ns_es_badlen; /* calculated bound mismatch */ + int ns_es_reflect; /* number of responses */ + int ns_es_inhist[NS_ERR_MAX]; + u_short ns_es_codes[NS_ERR_MAX];/* which error code for outhist + since we might not know all */ +}; + +#ifdef KERNEL +struct ns_errstat ns_errstat; +#endif + +#endif diff --git a/sys/netns/ns_if.h b/sys/netns/ns_if.h new file mode 100644 index 000000000000..a20012853ce8 --- /dev/null +++ b/sys/netns/ns_if.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_if.h 8.1 (Berkeley) 6/10/93 + * $Id: ns_if.h,v 1.4 1995/03/16 18:15:27 bde Exp $ + */ + +#ifndef _NETNS_NS_IF_H_ +#define _NETNS_NS_IF_H_ + +/* + * Interface address, xerox version. One of these structures + * is allocated for each interface with an internet address. + * The ifaddr structure contains the protocol-independent part + * of the structure and is assumed to be first. + */ + +struct ns_ifaddr { + struct ifaddr ia_ifa; /* protocol-independent info */ +#define ia_ifp ia_ifa.ifa_ifp +#define ia_flags ia_ifa.ifa_flags + struct ns_ifaddr *ia_next; /* next in list of xerox addresses */ + struct sockaddr_ns ia_addr; /* reserve space for my address */ + struct sockaddr_ns ia_dstaddr; /* space for my broadcast address */ +#define ia_broadaddr ia_dstaddr + struct sockaddr_ns ia_netmask; /* space for my network mask */ +}; + +struct ns_aliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_ns ifra_addr; + struct sockaddr_ns ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr +}; +/* + * Given a pointer to an ns_ifaddr (ifaddr), + * return a pointer to the addr as a sockadd_ns. + */ + +#define IA_SNS(ia) (&(((struct ns_ifaddr *)(ia))->ia_addr)) + +/* This is not the right place for this but where is? */ +#define ETHERTYPE_NS 0x0600 + +#ifdef NSIP +struct nsip_req { + struct sockaddr rq_ns; /* must be ns format destination */ + struct sockaddr rq_ip; /* must be ip format gateway */ + short rq_flags; +}; +#endif + +#ifdef KERNEL +struct ns_ifaddr *ns_ifaddr; +struct ns_ifaddr *ns_iaonnetof(); +void nsintr __P((void)); +struct ifqueue nsintrq; /* XNS input packet queue */ +#endif + +#endif diff --git a/sys/netns/ns_input.c b/sys/netns/ns_input.c new file mode 100644 index 000000000000..72245b208690 --- /dev/null +++ b/sys/netns/ns_input.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_input.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_input.c,v 1.5 1995/05/30 08:12:27 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> +#include <net/netisr.h> + +#include <netns/ns.h> +#include <netns/ns_if.h> +#include <netns/ns_pcb.h> +#include <netns/idp.h> +#include <netns/idp_var.h> +#include <netns/ns_error.h> + +/* + * NS initialization. + */ +union ns_host ns_thishost; +union ns_host ns_zerohost; +union ns_host ns_broadhost; +union ns_net ns_zeronet; +union ns_net ns_broadnet; +struct sockaddr_ns ns_netmask, ns_hostmask; + +static u_short allones[] = {-1, -1, -1}; + +struct nspcb nspcb; +struct nspcb nsrawpcb; + +struct ifqueue nsintrq; +int nsqmaxlen = IFQ_MAXLEN; + +int idpcksum = 1; +long ns_pexseq; + +ns_init() +{ + extern struct timeval time; + + ns_broadhost = * (union ns_host *) allones; + ns_broadnet = * (union ns_net *) allones; + nspcb.nsp_next = nspcb.nsp_prev = &nspcb; + nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb; + nsintrq.ifq_maxlen = nsqmaxlen; + ns_pexseq = time.tv_usec; + ns_netmask.sns_len = 6; + ns_netmask.sns_addr.x_net = ns_broadnet; + ns_hostmask.sns_len = 12; + ns_hostmask.sns_addr.x_net = ns_broadnet; + ns_hostmask.sns_addr.x_host = ns_broadhost; +} + +/* + * Idp input routine. Pass to next level. + */ +int nsintr_getpck = 0; +int nsintr_swtch = 0; +void +nsintr(void) +{ + register struct idp *idp; + register struct mbuf *m; + register struct nspcb *nsp; + register int i; + int len, s, error; + char oddpacketp; + +next: + /* + * Get next datagram off input queue and get IDP header + * in first mbuf. + */ + s = splimp(); + IF_DEQUEUE(&nsintrq, m); + splx(s); + nsintr_getpck++; + if (m == 0) + return; + if ((m->m_flags & M_EXT || m->m_len < sizeof (struct idp)) && + (m = m_pullup(m, sizeof (struct idp))) == 0) { + idpstat.idps_toosmall++; + goto next; + } + + /* + * Give any raw listeners a crack at the packet + */ + for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { + struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); + if (m1) idp_input(m1, nsp); + } + + idp = mtod(m, struct idp *); + len = ntohs(idp->idp_len); + if (oddpacketp = len & 1) { + len++; /* If this packet is of odd length, + preserve garbage byte for checksum */ + } + + /* + * Check that the amount of data in the buffers + * is as at least much as the IDP header would have us expect. + * Trim mbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_pkthdr.len < len) { + idpstat.idps_tooshort++; + goto bad; + } + if (m->m_pkthdr.len > len) { + if (m->m_len == m->m_pkthdr.len) { + m->m_len = len; + m->m_pkthdr.len = len; + } else + m_adj(m, len - m->m_pkthdr.len); + } + if (idpcksum && ((i = idp->idp_sum)!=0xffff)) { + idp->idp_sum = 0; + if (i != (idp->idp_sum = ns_cksum(m, len))) { + idpstat.idps_badsum++; + idp->idp_sum = i; + if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host)) + error = NS_ERR_BADSUM; + else + error = NS_ERR_BADSUM_T; + ns_error(m, error, 0); + goto next; + } + } + /* + * Is this a directed broadcast? + */ + if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) { + if ((!ns_neteq(idp->idp_dna, idp->idp_sna)) && + (!ns_neteqnn(idp->idp_dna.x_net, ns_broadnet)) && + (!ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)) && + (!ns_neteqnn(idp->idp_dna.x_net, ns_zeronet)) ) { + /* + * Look to see if I need to eat this packet. + * Algorithm is to forward all young packets + * and prematurely age any packets which will + * by physically broadcasted. + * Any very old packets eaten without forwarding + * would die anyway. + * + * Suggestion of Bill Nesheim, Cornell U. + */ + if (idp->idp_tc < NS_MAXHOPS) { + idp_forward(m); + goto next; + } + } + /* + * Is this our packet? If not, forward. + */ + } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) { + idp_forward(m); + goto next; + } + /* + * Locate pcb for datagram. + */ + nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD); + /* + * Switch out to protocol's input routine. + */ + nsintr_swtch++; + if (nsp) { + if (oddpacketp) { + m_adj(m, -1); + } + if ((nsp->nsp_flags & NSP_ALL_PACKETS)==0) + switch (idp->idp_pt) { + + case NSPROTO_SPP: + spp_input(m, nsp); + goto next; + + case NSPROTO_ERROR: + ns_err_input(m); + goto next; + } + idp_input(m, nsp); + } else { + ns_error(m, NS_ERR_NOSOCK, 0); + } + goto next; + +bad: + m_freem(m); + goto next; +} + +NETISR_SET(NETISR_NS, nsintr); + +u_char nsctlerrmap[PRC_NCMDS] = { + ECONNABORTED, ECONNABORTED, 0, 0, + 0, 0, EHOSTDOWN, EHOSTUNREACH, + ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, + EMSGSIZE, 0, 0, 0, + 0, 0, 0, 0 +}; + +int idp_donosocks = 1; + +idp_ctlinput(cmd, arg) + int cmd; + caddr_t arg; +{ + struct ns_addr *ns; + struct nspcb *nsp; + struct ns_errp *errp; + int idp_abort(); + extern struct nspcb *idp_drop(); + int type; + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + if (nsctlerrmap[cmd] == 0) + return; /* XXX */ + type = NS_ERR_UNREACH_HOST; + switch (cmd) { + struct sockaddr_ns *sns; + + case PRC_IFDOWN: + case PRC_HOSTDEAD: + case PRC_HOSTUNREACH: + sns = (struct sockaddr_ns *)arg; + if (sns->sns_family != AF_NS) + return; + ns = &sns->sns_addr; + break; + + default: + errp = (struct ns_errp *)arg; + ns = &errp->ns_err_idp.idp_dna; + type = errp->ns_err_num; + type = ntohs((u_short)type); + } + switch (type) { + + case NS_ERR_UNREACH_HOST: + ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, (long)0); + break; + + case NS_ERR_NOSOCK: + nsp = ns_pcblookup(ns, errp->ns_err_idp.idp_sna.x_port, + NS_WILDCARD); + if(nsp && idp_donosocks && ! ns_nullhost(nsp->nsp_faddr)) + (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); + } +} + +int idpprintfs = 0; +int idpforwarding = 1; +/* + * Forward a packet. If some error occurs return the sender + * an error packet. Note we can't always generate a meaningful + * error message because the NS errors don't have a large enough repetoire + * of codes and types. + */ +struct route idp_droute; +struct route idp_sroute; + +idp_forward(m) +struct mbuf *m; +{ + register struct idp *idp = mtod(m, struct idp *); + register int error, type, code; + struct mbuf *mcopy = NULL; + int agedelta = 1; + int flags = NS_FORWARDING; + int ok_there = 0; + int ok_back = 0; + + if (idpprintfs) { + printf("forward: src "); + ns_printhost(&idp->idp_sna); + printf(", dst "); + ns_printhost(&idp->idp_dna); + printf("hop count %d\n", idp->idp_tc); + } + if (idpforwarding == 0) { + /* can't tell difference between net and host */ + type = NS_ERR_UNREACH_HOST, code = 0; + goto senderror; + } + idp->idp_tc++; + if (idp->idp_tc > NS_MAXHOPS) { + type = NS_ERR_TOO_OLD, code = 0; + goto senderror; + } + /* + * Save at most 42 bytes of the packet in case + * we need to generate an NS error message to the src. + */ + mcopy = m_copy(m, 0, imin((int)ntohs(idp->idp_len), 42)); + + if ((ok_there = idp_do_route(&idp->idp_dna,&idp_droute))==0) { + type = NS_ERR_UNREACH_HOST, code = 0; + goto senderror; + } + /* + * Here we think about forwarding broadcast packets, + * so we try to insure that it doesn't go back out + * on the interface it came in on. Also, if we + * are going to physically broadcast this, let us + * age the packet so we can eat it safely the second time around. + */ + if (idp->idp_dna.x_host.c_host[0] & 0x1) { + struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); + struct ifnet *ifp; + if (ia) { + /* I'm gonna hafta eat this packet */ + agedelta += NS_MAXHOPS - idp->idp_tc; + idp->idp_tc = NS_MAXHOPS; + } + if ((ok_back = idp_do_route(&idp->idp_sna,&idp_sroute))==0) { + /* error = ENETUNREACH; He'll never get it! */ + m_freem(m); + goto cleanup; + } + if (idp_droute.ro_rt && + (ifp=idp_droute.ro_rt->rt_ifp) && + idp_sroute.ro_rt && + (ifp!=idp_sroute.ro_rt->rt_ifp)) { + flags |= NS_ALLOWBROADCAST; + } else { + type = NS_ERR_UNREACH_HOST, code = 0; + goto senderror; + } + } + /* need to adjust checksum */ + if (idp->idp_sum!=0xffff) { + union bytes { + u_char c[4]; + u_short s[2]; + long l; + } x; + register int shift; + x.l = 0; x.c[0] = agedelta; + shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf; + x.l = idp->idp_sum + (x.s[0] << shift); + x.l = x.s[0] + x.s[1]; + x.l = x.s[0] + x.s[1]; + if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l; + } + if ((error = ns_output(m, &idp_droute, flags)) && + (mcopy!=NULL)) { + idp = mtod(mcopy, struct idp *); + type = NS_ERR_UNSPEC_T, code = 0; + switch (error) { + + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + case ENETDOWN: + case EPERM: + type = NS_ERR_UNREACH_HOST; + break; + + case EMSGSIZE: + type = NS_ERR_TOO_BIG; + code = 576; /* too hard to figure out mtu here */ + break; + + case ENOBUFS: + type = NS_ERR_UNSPEC_T; + break; + } + mcopy = NULL; + senderror: + ns_error(m, type, code); + } +cleanup: + if (ok_there) + idp_undo_route(&idp_droute); + if (ok_back) + idp_undo_route(&idp_sroute); + if (mcopy != NULL) + m_freem(mcopy); +} + +idp_do_route(src, ro) +struct ns_addr *src; +struct route *ro; +{ + + struct sockaddr_ns *dst; + + bzero((caddr_t)ro, sizeof (*ro)); + dst = (struct sockaddr_ns *)&ro->ro_dst; + + dst->sns_len = sizeof(*dst); + dst->sns_family = AF_NS; + dst->sns_addr = *src; + dst->sns_addr.x_port = 0; + rtalloc(ro); + if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) { + return (0); + } + ro->ro_rt->rt_use++; + return (1); +} + +idp_undo_route(ro) +register struct route *ro; +{ + if (ro->ro_rt) {RTFREE(ro->ro_rt);} +} + +ns_watch_output(m, ifp) +struct mbuf *m; +struct ifnet *ifp; +{ + register struct nspcb *nsp; + register struct ifaddr *ifa; + /* + * Give any raw listeners a crack at the packet + */ + for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { + struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL); + if (m0) { + register struct idp *idp; + + M_PREPEND(m0, sizeof (*idp), M_DONTWAIT); + if (m0 == NULL) + continue; + idp = mtod(m0, struct idp *); + idp->idp_sna.x_net = ns_zeronet; + idp->idp_sna.x_host = ns_thishost; + if (ifp && (ifp->if_flags & IFF_POINTOPOINT)) + for(ifa = ifp->if_addrlist; ifa; + ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family==AF_NS) { + idp->idp_sna = IA_SNS(ifa)->sns_addr; + break; + } + } + idp->idp_len = ntohl(m0->m_pkthdr.len); + idp_input(m0, nsp); + } + } +} diff --git a/sys/netns/ns_ip.c b/sys/netns/ns_ip.c new file mode 100644 index 000000000000..44614a9f4d88 --- /dev/null +++ b/sys/netns/ns_ip.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_ip.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_ip.c,v 1.3 1995/03/19 14:29:03 davidg Exp $ + */ + +/* + * Software interface driver for encapsulating ns in ip. + */ + +#ifdef NSIP +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/netisr.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <machine/mtpr.h> + +#include <netns/ns.h> +#include <netns/ns_if.h> +#include <netns/idp.h> + +struct ifnet_en { + struct ifnet ifen_ifnet; + struct route ifen_route; + struct in_addr ifen_src; + struct in_addr ifen_dst; + struct ifnet_en *ifen_next; +}; + +int nsipoutput(), nsipioctl(), nsipstart(); +#define LOMTU (1024+512); + +struct ifnet nsipif; +struct ifnet_en *nsip_list; /* list of all hosts and gateways or + broadcast addrs */ + +struct ifnet_en * +nsipattach() +{ + register struct ifnet_en *m; + register struct ifnet *ifp; + + if (nsipif.if_mtu == 0) { + ifp = &nsipif; + ifp->if_name = "nsip"; + ifp->if_mtu = LOMTU; + ifp->if_ioctl = nsipioctl; + ifp->if_output = nsipoutput; + ifp->if_start = nsipstart; + ifp->if_flags = IFF_POINTOPOINT; + } + + MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT); + if (m == NULL) return (NULL); + m->ifen_next = nsip_list; + nsip_list = m; + ifp = &m->ifen_ifnet; + + ifp->if_name = "nsip"; + ifp->if_mtu = LOMTU; + ifp->if_ioctl = nsipioctl; + ifp->if_output = nsipoutput; + ifp->if_start = nsipstart; + ifp->if_flags = IFF_POINTOPOINT; + ifp->if_unit = nsipif.if_unit++; + if_attach(ifp); + + return (m); +} + + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +nsipioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + int error = 0; + struct ifreq *ifr; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* fall into: */ + + case SIOCSIFDSTADDR: + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCSIFFLAGS: + ifr = (struct ifreq *)data; + if ((ifr->ifr_flags & IFF_UP) == 0) + error = nsip_free(ifp); + + + default: + error = EINVAL; + } + return (error); +} + +struct mbuf *nsip_badlen; +struct mbuf *nsip_lastin; +int nsip_hold_input; + +idpip_input(m, ifp) + register struct mbuf *m; + struct ifnet *ifp; +{ + register struct ip *ip; + register struct idp *idp; + register struct ifqueue *ifq = &nsintrq; + int len, s; + + if (nsip_hold_input) { + if (nsip_lastin) { + m_freem(nsip_lastin); + } + nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT); + } + /* + * Get IP and IDP header together in first mbuf. + */ + nsipif.if_ipackets++; + s = sizeof (struct ip) + sizeof (struct idp); + if (((m->m_flags & M_EXT) || m->m_len < s) && + (m = m_pullup(m, s)) == 0) { + nsipif.if_ierrors++; + return; + } + ip = mtod(m, struct ip *); + if (ip->ip_hl > (sizeof (struct ip) >> 2)) { + ip_stripoptions(m, (struct mbuf *)0); + if (m->m_len < s) { + if ((m = m_pullup(m, s)) == 0) { + nsipif.if_ierrors++; + return; + } + ip = mtod(m, struct ip *); + } + } + + /* + * Make mbuf data length reflect IDP length. + * If not enough data to reflect IDP length, drop. + */ + m->m_data += sizeof (struct ip); + m->m_len -= sizeof (struct ip); + m->m_pkthdr.len -= sizeof (struct ip); + idp = mtod(m, struct idp *); + len = ntohs(idp->idp_len); + if (len & 1) len++; /* Preserve Garbage Byte */ + if (ip->ip_len != len) { + if (len > ip->ip_len) { + nsipif.if_ierrors++; + if (nsip_badlen) m_freem(nsip_badlen); + nsip_badlen = m; + return; + } + /* Any extra will be trimmed off by the NS routines */ + } + + /* + * Place interface pointer before the data + * for the receiving protocol. + */ + m->m_pkthdr.rcvif = ifp; + /* + * Deliver to NS + */ + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); +bad: + m_freem(m); + splx(s); + return; + } + IF_ENQUEUE(ifq, m); + schednetisr(NETISR_NS); + splx(s); + return; +} + +/* ARGSUSED */ +nsipoutput(ifn, m, dst) + struct ifnet_en *ifn; + register struct mbuf *m; + struct sockaddr *dst; +{ + + register struct ip *ip; + register struct route *ro = &(ifn->ifen_route); + register int len = 0; + register struct idp *idp = mtod(m, struct idp *); + int error; + + ifn->ifen_ifnet.if_opackets++; + nsipif.if_opackets++; + + + /* + * Calculate data length and make space + * for IP header. + */ + len = ntohs(idp->idp_len); + if (len & 1) len++; /* Preserve Garbage Byte */ + /* following clause not necessary on vax */ + if (3 & (int)m->m_data) { + /* force longword alignment of ip hdr */ + struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT); + if (m0 == 0) { + m_freem(m); + return (ENOBUFS); + } + MH_ALIGN(m0, sizeof (struct ip)); + m0->m_flags = m->m_flags & M_COPYFLAGS; + m0->m_next = m; + m0->m_len = sizeof (struct ip); + m0->m_pkthdr.len = m0->m_len + m->m_len; + m->m_flags &= ~M_PKTHDR; + } else { + M_PREPEND(m, sizeof (struct ip), M_DONTWAIT); + if (m == 0) + return (ENOBUFS); + } + /* + * Fill in IP header. + */ + ip = mtod(m, struct ip *); + *(long *)ip = 0; + ip->ip_p = IPPROTO_IDP; + ip->ip_src = ifn->ifen_src; + ip->ip_dst = ifn->ifen_dst; + ip->ip_len = (u_short)len + sizeof (struct ip); + ip->ip_ttl = MAXTTL; + + /* + * Output final datagram. + */ + error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST, NULL)); + if (error) { + ifn->ifen_ifnet.if_oerrors++; + ifn->ifen_ifnet.if_ierrors = error; + } + return (error); +bad: + m_freem(m); + return (ENETUNREACH); +} + +nsipstart(ifp) +struct ifnet *ifp; +{ + panic("nsip_start called"); +} + +struct ifreq ifr = {"nsip0"}; + +nsip_route(m) + register struct mbuf *m; +{ + register struct nsip_req *rq = mtod(m, struct nsip_req *); + struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; + struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; + struct route ro; + struct ifnet_en *ifn; + struct sockaddr_in *src; + + /* + * First, make sure we already have an ns address: + */ + if (ns_hosteqnh(ns_thishost, ns_zerohost)) + return (EADDRNOTAVAIL); + /* + * Now, determine if we can get to the destination + */ + bzero((caddr_t)&ro, sizeof (ro)); + ro.ro_dst = *(struct sockaddr *)ip_dst; + rtalloc(&ro); + if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { + return (ENETUNREACH); + } + + /* + * And see how he's going to get back to us: + * i.e., what return ip address do we use? + */ + { + register struct in_ifaddr *ia; + struct ifnet *ifp = ro.ro_rt->rt_ifp; + + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + if (ia == 0) + ia = in_ifaddr; + if (ia == 0) { + RTFREE(ro.ro_rt); + return (EADDRNOTAVAIL); + } + src = (struct sockaddr_in *)&ia->ia_addr; + } + + /* + * Is there a free (pseudo-)interface or space? + */ + for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) { + if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0) + break; + } + if (ifn == NULL) + ifn = nsipattach(); + if (ifn == NULL) { + RTFREE(ro.ro_rt); + return (ENOBUFS); + } + ifn->ifen_route = ro; + ifn->ifen_dst = ip_dst->sin_addr; + ifn->ifen_src = src->sin_addr; + + /* + * now configure this as a point to point link + */ + ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; + ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; + (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr, + (struct ifnet *)ifn); + satons_addr(ifr.ifr_addr).x_host = ns_thishost; + return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, + (struct ifnet *)ifn)); +} + +nsip_free(ifp) +struct ifnet *ifp; +{ + register struct ifnet_en *ifn = (struct ifnet_en *)ifp; + struct route *ro = & ifn->ifen_route; + + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = 0; + } + ifp->if_flags &= ~IFF_UP; + return (0); +} + +nsip_ctlinput(cmd, sa) + int cmd; + struct sockaddr *sa; +{ + extern u_char inetctlerrmap[]; + struct sockaddr_in *sin; + int in_rtchange(); + + if ((unsigned)cmd >= PRC_NCMDS) + return; + if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) + return; + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr == INADDR_ANY) + return; + + switch (cmd) { + + case PRC_ROUTEDEAD: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + nsip_rtchange(&sin->sin_addr); + break; + } +} + +nsip_rtchange(dst) + register struct in_addr *dst; +{ + register struct ifnet_en *ifn; + + for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) { + if (ifn->ifen_dst.s_addr == dst->s_addr && + ifn->ifen_route.ro_rt) { + RTFREE(ifn->ifen_route.ro_rt); + ifn->ifen_route.ro_rt = 0; + } + } +} +#endif diff --git a/sys/netns/ns_output.c b/sys/netns/ns_output.c new file mode 100644 index 000000000000..9d7715423831 --- /dev/null +++ b/sys/netns/ns_output.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_output.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_output.c,v 1.2 1994/08/02 07:51:51 davidg Exp $ + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netns/ns.h> +#include <netns/ns_if.h> +#include <netns/idp.h> +#include <netns/idp_var.h> + +#ifdef vax +#include <machine/mtpr.h> +#endif +int ns_hold_output = 0; +int ns_copy_output = 0; +int ns_output_cnt = 0; +struct mbuf *ns_lastout; + +ns_output(m0, ro, flags) + struct mbuf *m0; + struct route *ro; + int flags; +{ + register struct idp *idp = mtod(m0, struct idp *); + register struct ifnet *ifp = 0; + int error = 0; + struct route idproute; + struct sockaddr_ns *dst; + extern int idpcksum; + + if (ns_hold_output) { + if (ns_lastout) { + (void)m_free(ns_lastout); + } + ns_lastout = m_copy(m0, 0, (int)M_COPYALL); + } + /* + * Route packet. + */ + if (ro == 0) { + ro = &idproute; + bzero((caddr_t)ro, sizeof (*ro)); + } + dst = (struct sockaddr_ns *)&ro->ro_dst; + if (ro->ro_rt == 0) { + dst->sns_family = AF_NS; + dst->sns_len = sizeof (*dst); + dst->sns_addr = idp->idp_dna; + dst->sns_addr.x_port = 0; + /* + * If routing to interface only, + * short circuit routing lookup. + */ + if (flags & NS_ROUTETOIF) { + struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); + + if (ia == 0) { + error = ENETUNREACH; + goto bad; + } + ifp = ia->ia_ifp; + goto gotif; + } + rtalloc(ro); + } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) { + /* + * The old route has gone away; try for a new one. + */ + rtfree(ro->ro_rt); + ro->ro_rt = NULL; + rtalloc(ro); + } + if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { + error = ENETUNREACH; + goto bad; + } + ro->ro_rt->rt_use++; + if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) + dst = (struct sockaddr_ns *)ro->ro_rt->rt_gateway; +gotif: + + /* + * Look for multicast addresses and + * and verify user is allowed to send + * such a packet. + */ + if (dst->sns_addr.x_host.c_host[0]&1) { + if ((ifp->if_flags & IFF_BROADCAST) == 0) { + error = EADDRNOTAVAIL; + goto bad; + } + if ((flags & NS_ALLOWBROADCAST) == 0) { + error = EACCES; + goto bad; + } + } + + if (htons(idp->idp_len) <= ifp->if_mtu) { + ns_output_cnt++; + if (ns_copy_output) { + ns_watch_output(m0, ifp); + } + error = (*ifp->if_output)(ifp, m0, + (struct sockaddr *)dst, ro->ro_rt); + goto done; + } else error = EMSGSIZE; + + +bad: + if (ns_copy_output) { + ns_watch_output(m0, ifp); + } + m_freem(m0); +done: + if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = 0; + } + return (error); +} diff --git a/sys/netns/ns_pcb.c b/sys/netns/ns_pcb.c new file mode 100644 index 000000000000..1b07c3211946 --- /dev/null +++ b/sys/netns/ns_pcb.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_pcb.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_pcb.c,v 1.3 1995/05/30 08:12:28 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netns/ns.h> +#include <netns/ns_if.h> +#include <netns/ns_pcb.h> + +struct ns_addr zerons_addr; + +ns_pcballoc(so, head) + struct socket *so; + struct nspcb *head; +{ + struct mbuf *m; + register struct nspcb *nsp; + + m = m_getclr(M_DONTWAIT, MT_PCB); + if (m == NULL) + return (ENOBUFS); + nsp = mtod(m, struct nspcb *); + nsp->nsp_socket = so; + insque(nsp, head); + so->so_pcb = (caddr_t)nsp; + return (0); +} + +ns_pcbbind(nsp, nam) + register struct nspcb *nsp; + struct mbuf *nam; +{ + register struct sockaddr_ns *sns; + u_short lport = 0; + + if (nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr)) + return (EINVAL); + if (nam == 0) + goto noname; + sns = mtod(nam, struct sockaddr_ns *); + if (nam->m_len != sizeof (*sns)) + return (EINVAL); + if (!ns_nullhost(sns->sns_addr)) { + int tport = sns->sns_port; + + sns->sns_port = 0; /* yech... */ + if (ifa_ifwithaddr((struct sockaddr *)sns) == 0) + return (EADDRNOTAVAIL); + sns->sns_port = tport; + } + lport = sns->sns_port; + if (lport) { + u_short aport = ntohs(lport); + + if (aport < NSPORT_RESERVED && + (nsp->nsp_socket->so_state & SS_PRIV) == 0) + return (EACCES); + if (ns_pcblookup(&zerons_addr, lport, 0)) + return (EADDRINUSE); + } + nsp->nsp_laddr = sns->sns_addr; +noname: + if (lport == 0) + do { + if (nspcb.nsp_lport++ < NSPORT_RESERVED) + nspcb.nsp_lport = NSPORT_RESERVED; + lport = htons(nspcb.nsp_lport); + } while (ns_pcblookup(&zerons_addr, lport, 0)); + nsp->nsp_lport = lport; + return (0); +} + +/* + * Connect from a socket to a specified address. + * Both address and port must be specified in argument sns. + * If don't have a local address for this socket yet, + * then pick one. + */ +ns_pcbconnect(nsp, nam) + struct nspcb *nsp; + struct mbuf *nam; +{ + struct ns_ifaddr *ia; + register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); + register struct ns_addr *dst; + register struct route *ro; + struct ifnet *ifp; + + if (nam->m_len != sizeof (*sns)) + return (EINVAL); + if (sns->sns_family != AF_NS) + return (EAFNOSUPPORT); + if (sns->sns_port==0 || ns_nullhost(sns->sns_addr)) + return (EADDRNOTAVAIL); + /* + * If we haven't bound which network number to use as ours, + * we will use the number of the outgoing interface. + * This depends on having done a routing lookup, which + * we will probably have to do anyway, so we might + * as well do it now. On the other hand if we are + * sending to multiple destinations we may have already + * done the lookup, so see if we can use the route + * from before. In any case, we only + * chose a port number once, even if sending to multiple + * destinations. + */ + ro = &nsp->nsp_route; + dst = &satons_addr(ro->ro_dst); + if (nsp->nsp_socket->so_options & SO_DONTROUTE) + goto flush; + if (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) + goto flush; + if (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr)) { + if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) { + /* can patch route to avoid rtalloc */ + *dst = sns->sns_addr; + } else { + flush: + if (ro->ro_rt) + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + nsp->nsp_laddr.x_net = ns_zeronet; + } + }/* else cached route is ok; do nothing */ + nsp->nsp_lastdst = sns->sns_addr; + if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ + (ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + /* No route yet, so try to acquire one */ + ro->ro_dst.sa_family = AF_NS; + ro->ro_dst.sa_len = sizeof(ro->ro_dst); + *dst = sns->sns_addr; + dst->x_port = 0; + rtalloc(ro); + } + if (ns_neteqnn(nsp->nsp_laddr.x_net, ns_zeronet)) { + /* + * If route is known or can be allocated now, + * our src addr is taken from the i/f, else punt. + */ + + ia = (struct ns_ifaddr *)0; + /* + * If we found a route, use the address + * corresponding to the outgoing interface + */ + if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) + for (ia = ns_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + if (ia == 0) { + u_short fport = sns->sns_addr.x_port; + sns->sns_addr.x_port = 0; + ia = (struct ns_ifaddr *) + ifa_ifwithdstaddr((struct sockaddr *)sns); + sns->sns_addr.x_port = fport; + if (ia == 0) + ia = ns_iaonnetof(&sns->sns_addr); + if (ia == 0) + ia = ns_ifaddr; + if (ia == 0) + return (EADDRNOTAVAIL); + } + nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net; + } + if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0)) + return (EADDRINUSE); + if (ns_nullhost(nsp->nsp_laddr)) { + if (nsp->nsp_lport == 0) + (void) ns_pcbbind(nsp, (struct mbuf *)0); + nsp->nsp_laddr.x_host = ns_thishost; + } + nsp->nsp_faddr = sns->sns_addr; + /* Includes nsp->nsp_fport = sns->sns_port; */ + return (0); +} + +ns_pcbdisconnect(nsp) + struct nspcb *nsp; +{ + + nsp->nsp_faddr = zerons_addr; + if (nsp->nsp_socket->so_state & SS_NOFDREF) + ns_pcbdetach(nsp); +} + +ns_pcbdetach(nsp) + struct nspcb *nsp; +{ + struct socket *so = nsp->nsp_socket; + + so->so_pcb = 0; + sofree(so); + if (nsp->nsp_route.ro_rt) + rtfree(nsp->nsp_route.ro_rt); + remque(nsp); + (void) m_free(dtom(nsp)); +} + +ns_setsockaddr(nsp, nam) + register struct nspcb *nsp; + struct mbuf *nam; +{ + register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); + + nam->m_len = sizeof (*sns); + sns = mtod(nam, struct sockaddr_ns *); + bzero((caddr_t)sns, sizeof (*sns)); + sns->sns_len = sizeof(*sns); + sns->sns_family = AF_NS; + sns->sns_addr = nsp->nsp_laddr; +} + +ns_setpeeraddr(nsp, nam) + register struct nspcb *nsp; + struct mbuf *nam; +{ + register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); + + nam->m_len = sizeof (*sns); + sns = mtod(nam, struct sockaddr_ns *); + bzero((caddr_t)sns, sizeof (*sns)); + sns->sns_len = sizeof(*sns); + sns->sns_family = AF_NS; + sns->sns_addr = nsp->nsp_faddr; +} + +/* + * Pass some notification to all connections of a protocol + * associated with address dst. Call the + * protocol specific routine to handle each connection. + * Also pass an extra paramter via the nspcb. (which may in fact + * be a parameter list!) + */ +ns_pcbnotify(dst, errno, notify, param) + register struct ns_addr *dst; + long param; + int errno, (*notify)(); +{ + register struct nspcb *nsp, *oinp; + int s = splimp(); + + for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { + if (!ns_hosteq(*dst,nsp->nsp_faddr)) { + next: + nsp = nsp->nsp_next; + continue; + } + if (nsp->nsp_socket == 0) + goto next; + if (errno) + nsp->nsp_socket->so_error = errno; + oinp = nsp; + nsp = nsp->nsp_next; + oinp->nsp_notify_param = param; + (*notify)(oinp); + } + splx(s); +} + +#ifdef notdef +/* + * After a routing change, flush old routing + * and allocate a (hopefully) better one. + */ +ns_rtchange(nsp) + struct nspcb *nsp; +{ + if (nsp->nsp_route.ro_rt) { + rtfree(nsp->nsp_route.ro_rt); + nsp->nsp_route.ro_rt = 0; + /* + * A new route can be allocated the next time + * output is attempted. + */ + } + /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ +} +#endif + +struct nspcb * +ns_pcblookup(faddr, lport, wildp) + struct ns_addr *faddr; + u_short lport; +{ + register struct nspcb *nsp, *match = 0; + int matchwild = 3, wildcard; + u_short fport; + + fport = faddr->x_port; + for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { + if (nsp->nsp_lport != lport) + continue; + wildcard = 0; + if (ns_nullhost(nsp->nsp_faddr)) { + if (!ns_nullhost(*faddr)) + wildcard++; + } else { + if (ns_nullhost(*faddr)) + wildcard++; + else { + if (!ns_hosteq(nsp->nsp_faddr, *faddr)) + continue; + if (nsp->nsp_fport != fport) { + if (nsp->nsp_fport != 0) + continue; + else + wildcard++; + } + } + } + if (wildcard && wildp==0) + continue; + if (wildcard < matchwild) { + match = nsp; + matchwild = wildcard; + if (wildcard == 0) + break; + } + } + return (match); +} diff --git a/sys/netns/ns_pcb.h b/sys/netns/ns_pcb.h new file mode 100644 index 000000000000..3260113f4b84 --- /dev/null +++ b/sys/netns/ns_pcb.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_pcb.h 8.1 (Berkeley) 6/10/93 + * $Id: ns_pcb.h,v 1.3 1994/08/21 06:22:09 paul Exp $ + */ + +#ifndef _NETNS_NS_PCB_H_ +#define _NETNS_NS_PCB_H_ + +/* + * Ns protocol interface control block. + */ +struct nspcb { + struct nspcb *nsp_next; /* doubly linked list */ + struct nspcb *nsp_prev; + struct nspcb *nsp_head; + struct socket *nsp_socket; /* back pointer to socket */ + struct ns_addr nsp_faddr; /* destination address */ + struct ns_addr nsp_laddr; /* socket's address */ + caddr_t nsp_pcb; /* protocol specific stuff */ + struct route nsp_route; /* routing information */ + struct ns_addr nsp_lastdst; /* validate cached route for dg socks*/ + long nsp_notify_param; /* extra info passed via ns_pcbnotify*/ + short nsp_flags; + u_char nsp_dpt; /* default packet type for idp_output*/ + u_char nsp_rpt; /* last received packet type by + idp_input() */ +}; + +/* possible flags */ + +#define NSP_IN_ABORT 0x1 /* calling abort through socket */ +#define NSP_RAWIN 0x2 /* show headers on input */ +#define NSP_RAWOUT 0x4 /* show header on output */ +#define NSP_ALL_PACKETS 0x8 /* Turn off higher proto processing */ + +#define NS_WILDCARD 1 + +#define nsp_lport nsp_laddr.x_port +#define nsp_fport nsp_faddr.x_port + +#define sotonspcb(so) ((struct nspcb *)((so)->so_pcb)) + +/* + * Nominal space allocated to a ns socket. + */ +#define NSSNDQ 2048 +#define NSRCVQ 2048 + + +#ifdef KERNEL +struct nspcb nspcb; /* head of list */ +struct nspcb *ns_pcblookup(); +#endif + +#endif diff --git a/sys/netns/ns_proto.c b/sys/netns/ns_proto.c new file mode 100644 index 000000000000..87b16522bfec --- /dev/null +++ b/sys/netns/ns_proto.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)ns_proto.c 8.1 (Berkeley) 6/10/93 + * $Id: ns_proto.c,v 1.4 1995/05/30 08:12:30 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <sys/mbuf.h> + +#include <net/radix.h> + +#include <netns/ns.h> + +/* + * NS protocol family: IDP, ERR, PE, SPP, ROUTE. + */ +int ns_init(); +int idp_input(), idp_output(), idp_ctlinput(), idp_usrreq(); +int idp_raw_usrreq(), idp_ctloutput(); +int spp_input(), spp_ctlinput(); +int spp_usrreq(), spp_usrreq_sp(), spp_ctloutput(); +int spp_init(), spp_fasttimo(), spp_slowtimo(); +extern int raw_usrreq(); + +extern struct domain nsdomain; + +struct protosw nssw[] = { +{ 0, &nsdomain, 0, 0, + 0, idp_output, 0, 0, + 0, + ns_init, 0, 0, 0, +}, +{ SOCK_DGRAM, &nsdomain, 0, PR_ATOMIC|PR_ADDR, + 0, 0, idp_ctlinput, idp_ctloutput, + idp_usrreq, + 0, 0, 0, 0, +}, +{ SOCK_STREAM, &nsdomain, NSPROTO_SPP, PR_CONNREQUIRED|PR_WANTRCVD, + spp_input, 0, spp_ctlinput, spp_ctloutput, + spp_usrreq, + spp_init, spp_fasttimo, spp_slowtimo, 0, +}, +{ SOCK_SEQPACKET,&nsdomain, NSPROTO_SPP, PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC, + spp_input, 0, spp_ctlinput, spp_ctloutput, + spp_usrreq_sp, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &nsdomain, NSPROTO_RAW, PR_ATOMIC|PR_ADDR, + idp_input, idp_output, 0, idp_ctloutput, + idp_raw_usrreq, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &nsdomain, NSPROTO_ERROR, PR_ATOMIC|PR_ADDR, + idp_ctlinput, idp_output, 0, idp_ctloutput, + idp_raw_usrreq, + 0, 0, 0, 0, +}, +}; + +struct domain nsdomain = + { AF_NS, "network systems", 0, 0, 0, + nssw, &nssw[sizeof(nssw)/sizeof(nssw[0])], 0, + rn_inithead, 16, sizeof(struct sockaddr_ns)}; + +DOMAIN_SET(ns); diff --git a/sys/netns/sp.h b/sys/netns/sp.h new file mode 100644 index 000000000000..1f50e6e1d13d --- /dev/null +++ b/sys/netns/sp.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)sp.h 8.1 (Berkeley) 6/10/93 + * $Id: sp.h,v 1.3 1994/08/21 06:22:09 paul Exp $ + */ + +#ifndef _NETNS_SP_H_ +#define _NETNS_SP_H_ + +/* + * Definitions for Xerox NS style sequenced packet protocol + */ + +struct sphdr { + u_char sp_cc; /* connection control */ + u_char sp_dt; /* datastream type */ +#define SP_SP 0x80 /* system packet */ +#define SP_SA 0x40 /* send acknowledgement */ +#define SP_OB 0x20 /* attention (out of band data) */ +#define SP_EM 0x10 /* end of message */ + u_short sp_sid; /* source connection identifier */ + u_short sp_did; /* destination connection identifier */ + u_short sp_seq; /* sequence number */ + u_short sp_ack; /* acknowledge number */ + u_short sp_alo; /* allocation number */ +}; + +#endif diff --git a/sys/netns/spidp.h b/sys/netns/spidp.h new file mode 100644 index 000000000000..52fdf786e330 --- /dev/null +++ b/sys/netns/spidp.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spidp.h 8.1 (Berkeley) 6/10/93 + * $Id: spidp.h,v 1.3 1994/08/21 06:22:10 paul Exp $ + */ + +#ifndef _NETNS_SPIDP_H_ +#define _NETNS_SPIDP_H_ + +/* + * Definitions for NS(tm) Internet Datagram Protocol + * containing a Sequenced Packet Protocol packet. + */ +struct spidp { + struct idp si_i; + struct sphdr si_s; +}; +struct spidp_q { + struct spidp_q *si_next; + struct spidp_q *si_prev; +}; +#define SI(x) ((struct spidp *)x) +#define si_sum si_i.idp_sum +#define si_len si_i.idp_len +#define si_tc si_i.idp_tc +#define si_pt si_i.idp_pt +#define si_dna si_i.idp_dna +#define si_sna si_i.idp_sna +#define si_sport si_i.idp_sna.x_port +#define si_cc si_s.sp_cc +#define si_dt si_s.sp_dt +#define si_sid si_s.sp_sid +#define si_did si_s.sp_did +#define si_seq si_s.sp_seq +#define si_ack si_s.sp_ack +#define si_alo si_s.sp_alo + +#endif diff --git a/sys/netns/spp_debug.c b/sys/netns/spp_debug.c new file mode 100644 index 000000000000..982c9aa14150 --- /dev/null +++ b/sys/netns/spp_debug.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spp_debug.c 8.1 (Berkeley) 6/10/93 + * $Id: spp_debug.c,v 1.2 1994/08/02 07:51:57 davidg Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/route.h> +#include <net/if.h> +#include <netinet/tcp_fsm.h> + +#include <netns/ns.h> +#include <netns/ns_pcb.h> +#include <netns/idp.h> +#include <netns/idp_var.h> +#include <netns/sp.h> +#include <netns/spidp.h> +#define SPPTIMERS +#include <netns/spp_timer.h> +#include <netns/spp_var.h> +#define SANAMES +#include <netns/spp_debug.h> + +int sppconsdebug = 0; +/* + * spp debug routines + */ +spp_trace(act, ostate, sp, si, req) + short act; + u_char ostate; + struct sppcb *sp; + struct spidp *si; + int req; +{ +#ifdef INET +#ifdef TCPDEBUG + u_short seq, ack, len, alo; + unsigned long iptime(); + int flags; + struct spp_debug *sd = &spp_debug[spp_debx++]; + extern char *prurequests[]; + extern char *sanames[]; + extern char *tcpstates[]; + extern char *spptimers[]; + + if (spp_debx == SPP_NDEBUG) + spp_debx = 0; + sd->sd_time = iptime(); + sd->sd_act = act; + sd->sd_ostate = ostate; + sd->sd_cb = (caddr_t)sp; + if (sp) + sd->sd_sp = *sp; + else + bzero((caddr_t)&sd->sd_sp, sizeof (*sp)); + if (si) + sd->sd_si = *si; + else + bzero((caddr_t)&sd->sd_si, sizeof (*si)); + sd->sd_req = req; + if (sppconsdebug == 0) + return; + if (ostate >= TCP_NSTATES) ostate = 0; + if (act >= SA_DROP) act = SA_DROP; + if (sp) + printf("%x %s:", sp, tcpstates[ostate]); + else + printf("???????? "); + printf("%s ", sanames[act]); + switch (act) { + + case SA_RESPOND: + case SA_INPUT: + case SA_OUTPUT: + case SA_DROP: + if (si == 0) + break; + seq = si->si_seq; + ack = si->si_ack; + alo = si->si_alo; + len = si->si_len; + if (act == SA_OUTPUT) { + seq = ntohs(seq); + ack = ntohs(ack); + alo = ntohs(alo); + len = ntohs(len); + } +#ifndef lint +#define p1(f) { printf("%s = %x, ", "f", f); } + p1(seq); p1(ack); p1(alo); p1(len); +#endif + flags = si->si_cc; + if (flags) { + char *cp = "<"; +#ifndef lint +#define pf(f) { if (flags&SP_/**/f) { printf("%s%s", cp, "f"); cp = ","; } } + pf(SP); pf(SA); pf(OB); pf(EM); +#else + cp = cp; +#endif + printf(">"); + } +#ifndef lint +#define p2(f) { printf("%s = %x, ", "f", si->si_/**/f); } + p2(sid);p2(did);p2(dt);p2(pt); +#endif + ns_printhost(&si->si_sna); + ns_printhost(&si->si_dna); + + if (act==SA_RESPOND) { + printf("idp_len = %x, ", + ((struct idp *)si)->idp_len); + } + break; + + case SA_USER: + printf("%s", prurequests[req&0xff]); + if ((req & 0xff) == PRU_SLOWTIMO) + printf("<%s>", spptimers[req>>8]); + break; + } + if (sp) + printf(" -> %s", tcpstates[sp->s_state]); + /* print out internal state of sp !?! */ + printf("\n"); + if (sp == 0) + return; +#ifndef lint +#define p3(f) { printf("%s = %x, ", "f", sp->s_/**/f); } + printf("\t"); p3(rack);p3(ralo);p3(smax);p3(flags); printf("\n"); +#endif +#endif +#endif +} diff --git a/sys/netns/spp_debug.h b/sys/netns/spp_debug.h new file mode 100644 index 000000000000..0f5b0930b6cd --- /dev/null +++ b/sys/netns/spp_debug.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spp_debug.h 8.1 (Berkeley) 6/10/93 + * $Id: spp_debug.h,v 1.3 1994/08/21 06:22:11 paul Exp $ + */ + +#ifndef _NETNS_SPP_DEBUG_H_ +#define _NETNS_SPP_DEBUG_H_ + +struct spp_debug { + u_long sd_time; + short sd_act; + short sd_ostate; + caddr_t sd_cb; + short sd_req; + struct spidp sd_si; + struct sppcb sd_sp; +}; + +#define SA_INPUT 0 +#define SA_OUTPUT 1 +#define SA_USER 2 +#define SA_RESPOND 3 +#define SA_DROP 4 + +#ifdef SANAMES +char *sanames[] = + { "input", "output", "user", "respond", "drop" }; +#endif + +#define SPP_NDEBUG 100 +struct spp_debug spp_debug[SPP_NDEBUG]; +int spp_debx; + +#endif diff --git a/sys/netns/spp_timer.h b/sys/netns/spp_timer.h new file mode 100644 index 000000000000..972fd6ab8d82 --- /dev/null +++ b/sys/netns/spp_timer.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spp_timer.h 8.1 (Berkeley) 6/10/93 + * $Id: spp_timer.h,v 1.3 1994/08/21 06:22:11 paul Exp $ + */ + +#ifndef _NETNS_SPP_TIMER_H_ +#define _NETNS_SPP_TIMER_H_ + +/* + * Definitions of the SPP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define SPPT_NTIMERS 4 + +#define SPPT_REXMT 0 /* retransmit */ +#define SPPT_PERSIST 1 /* retransmit persistance */ +#define SPPT_KEEP 2 /* keep alive */ +#define SPPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The SPPT_REXMT timer is used to force retransmissions. + * The SPP has the SPPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The SPPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the SPPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as SPPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The SPPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The SPPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for SPPTV_KEEP amount of time, + * but not yet established, then we drop the connection. If the connection + * is established, then we force the peer to send us a segment by sending: + * <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK> + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the SPPT_KEEP + * initiated segments we cannot elicit a response from a peer in SPPT_MAXIDLE + * amount of time, then we drop the connection. + */ + +#define SPP_TTL 30 /* default time to live for SPP segs */ +/* + * Time constants. + */ +#define SPPTV_MSL ( 15*PR_SLOWHZ) /* max seg lifetime */ +#define SPPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define SPPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define SPPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistance */ +#define SPPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define SPPTV_KEEP ( 75*PR_SLOWHZ) /* keep alive - 75 secs */ +#define SPPTV_MAXIDLE ( 8*SPPTV_KEEP) /* maximum allowable idle + time before drop conn */ + +#define SPPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +#define SPPTV_REXMTMAX ( 64*PR_SLOWHZ) /* max allowable REXMT value */ + +#define SPP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define SPP_MAXRXTSHIFT 12 /* maximum retransmits */ + +#ifdef SPPTIMERS +char *spptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define SPPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +#ifdef KERNEL +extern int spp_backoff[]; +#endif + +#endif diff --git a/sys/netns/spp_usrreq.c b/sys/netns/spp_usrreq.c new file mode 100644 index 000000000000..8a78580dfd03 --- /dev/null +++ b/sys/netns/spp_usrreq.c @@ -0,0 +1,1805 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spp_usrreq.c 8.1 (Berkeley) 6/10/93 + * $Id: spp_usrreq.c,v 1.4 1995/05/30 08:12:31 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> +#include <netinet/tcp_fsm.h> + +#include <netns/ns.h> +#include <netns/ns_pcb.h> +#include <netns/idp.h> +#include <netns/idp_var.h> +#include <netns/ns_error.h> +#include <netns/sp.h> +#include <netns/spidp.h> +#include <netns/spp_timer.h> +#include <netns/spp_var.h> +#include <netns/spp_debug.h> + +/* + * SP protocol implementation. + */ +spp_init() +{ + + spp_iss = 1; /* WRONG !! should fish it out of TODR */ +} +struct spidp spp_savesi; +int traceallspps = 0; +extern int sppconsdebug; +int spp_hardnosed; +int spp_use_delack = 0; +u_short spp_newchecks[50]; + +/*ARGSUSED*/ +spp_input(m, nsp) + register struct mbuf *m; + register struct nspcb *nsp; +{ + register struct sppcb *cb; + register struct spidp *si = mtod(m, struct spidp *); + register struct socket *so; + short ostate; + int dropsocket = 0; + + + sppstat.spps_rcvtotal++; + if (nsp == 0) { + panic("No nspcb in spp_input"); + return; + } + + cb = nstosppcb(nsp); + if (cb == 0) goto bad; + + if (m->m_len < sizeof(*si)) { + if ((m = m_pullup(m, sizeof(*si))) == 0) { + sppstat.spps_rcvshort++; + return; + } + si = mtod(m, struct spidp *); + } + si->si_seq = ntohs(si->si_seq); + si->si_ack = ntohs(si->si_ack); + si->si_alo = ntohs(si->si_alo); + + so = nsp->nsp_socket; + if (so->so_options & SO_DEBUG || traceallspps) { + ostate = cb->s_state; + spp_savesi = *si; + } + if (so->so_options & SO_ACCEPTCONN) { + struct sppcb *ocb = cb; + + so = sonewconn(so, 0); + if (so == 0) { + goto drop; + } + /* + * This is ugly, but .... + * + * Mark socket as temporary until we're + * committed to keeping it. The code at + * ``drop'' and ``dropwithreset'' check the + * flag dropsocket to see if the temporary + * socket created here should be discarded. + * We mark the socket as discardable until + * we're committed to it below in TCPS_LISTEN. + */ + dropsocket++; + nsp = (struct nspcb *)so->so_pcb; + nsp->nsp_laddr = si->si_dna; + cb = nstosppcb(nsp); + cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ + cb->s_flags = ocb->s_flags; /* preserve sockopts */ + cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ + cb->s_state = TCPS_LISTEN; + } + + /* + * Packet received on connection. + * reset idle time and keep-alive timer; + */ + cb->s_idle = 0; + cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + + switch (cb->s_state) { + + case TCPS_LISTEN:{ + struct mbuf *am; + register struct sockaddr_ns *sns; + struct ns_addr laddr; + + /* + * If somebody here was carying on a conversation + * and went away, and his pen pal thinks he can + * still talk, we get the misdirected packet. + */ + if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { + spp_istat.gonawy++; + goto dropwithreset; + } + am = m_get(M_DONTWAIT, MT_SONAME); + if (am == NULL) + goto drop; + am->m_len = sizeof (struct sockaddr_ns); + sns = mtod(am, struct sockaddr_ns *); + sns->sns_len = sizeof(*sns); + sns->sns_family = AF_NS; + sns->sns_addr = si->si_sna; + laddr = nsp->nsp_laddr; + if (ns_nullhost(laddr)) + nsp->nsp_laddr = si->si_dna; + if (ns_pcbconnect(nsp, am)) { + nsp->nsp_laddr = laddr; + (void) m_free(am); + spp_istat.noconn++; + goto drop; + } + (void) m_free(am); + spp_template(cb); + dropsocket = 0; /* committed to socket */ + cb->s_did = si->si_sid; + cb->s_rack = si->si_ack; + cb->s_ralo = si->si_alo; +#define THREEWAYSHAKE +#ifdef THREEWAYSHAKE + cb->s_state = TCPS_SYN_RECEIVED; + cb->s_force = 1 + SPPT_KEEP; + sppstat.spps_accepts++; + cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + } + break; + /* + * This state means that we have heard a response + * to our acceptance of their connection + * It is probably logically unnecessary in this + * implementation. + */ + case TCPS_SYN_RECEIVED: { + if (si->si_did!=cb->s_sid) { + spp_istat.wrncon++; + goto drop; + } +#endif + nsp->nsp_fport = si->si_sport; + cb->s_timer[SPPT_REXMT] = 0; + cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + soisconnected(so); + cb->s_state = TCPS_ESTABLISHED; + sppstat.spps_accepts++; + } + break; + + /* + * This state means that we have gotten a response + * to our attempt to establish a connection. + * We fill in the data from the other side, + * telling us which port to respond to, instead of the well- + * known one we might have sent to in the first place. + * We also require that this is a response to our + * connection id. + */ + case TCPS_SYN_SENT: + if (si->si_did!=cb->s_sid) { + spp_istat.notme++; + goto drop; + } + sppstat.spps_connects++; + cb->s_did = si->si_sid; + cb->s_rack = si->si_ack; + cb->s_ralo = si->si_alo; + cb->s_dport = nsp->nsp_fport = si->si_sport; + cb->s_timer[SPPT_REXMT] = 0; + cb->s_flags |= SF_ACKNOW; + soisconnected(so); + cb->s_state = TCPS_ESTABLISHED; + /* Use roundtrip time of connection request for initial rtt */ + if (cb->s_rtt) { + cb->s_srtt = cb->s_rtt << 3; + cb->s_rttvar = cb->s_rtt << 1; + SPPT_RANGESET(cb->s_rxtcur, + ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, + SPPTV_MIN, SPPTV_REXMTMAX); + cb->s_rtt = 0; + } + } + if (so->so_options & SO_DEBUG || traceallspps) + spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); + + m->m_len -= sizeof (struct idp); + m->m_pkthdr.len -= sizeof (struct idp); + m->m_data += sizeof (struct idp); + + if (spp_reass(cb, si)) { + (void) m_freem(m); + } + if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) + (void) spp_output(cb, (struct mbuf *)0); + cb->s_flags &= ~(SF_WIN|SF_RXT); + return; + +dropwithreset: + if (dropsocket) + (void) soabort(so); + si->si_seq = ntohs(si->si_seq); + si->si_ack = ntohs(si->si_ack); + si->si_alo = ntohs(si->si_alo); + ns_error(dtom(si), NS_ERR_NOSOCK, 0); + if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) + spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); + return; + +drop: +bad: + if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || + traceallspps) + spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); + m_freem(m); +} + +int spprexmtthresh = 3; + +/* + * This is structurally similar to the tcp reassembly routine + * but its function is somewhat different: It merely queues + * packets up, and suppresses duplicates. + */ +spp_reass(cb, si) +register struct sppcb *cb; +register struct spidp *si; +{ + register struct spidp_q *q; + register struct mbuf *m; + register struct socket *so = cb->s_nspcb->nsp_socket; + char packetp = cb->s_flags & SF_HI; + int incr; + char wakeup = 0; + + if (si == SI(0)) + goto present; + /* + * Update our news from them. + */ + if (si->si_cc & SP_SA) + cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW); + if (SSEQ_GT(si->si_alo, cb->s_ralo)) + cb->s_flags |= SF_WIN; + if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { + if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) { + sppstat.spps_rcvdupack++; + /* + * If this is a completely duplicate ack + * and other conditions hold, we assume + * a packet has been dropped and retransmit + * it exactly as in tcp_input(). + */ + if (si->si_ack != cb->s_rack || + si->si_alo != cb->s_ralo) + cb->s_dupacks = 0; + else if (++cb->s_dupacks == spprexmtthresh) { + u_short onxt = cb->s_snxt; + int cwnd = cb->s_cwnd; + + cb->s_snxt = si->si_ack; + cb->s_cwnd = CUNIT; + cb->s_force = 1 + SPPT_REXMT; + (void) spp_output(cb, (struct mbuf *)0); + cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; + cb->s_rtt = 0; + if (cwnd >= 4 * CUNIT) + cb->s_cwnd = cwnd / 2; + if (SSEQ_GT(onxt, cb->s_snxt)) + cb->s_snxt = onxt; + return (1); + } + } else + cb->s_dupacks = 0; + goto update_window; + } + cb->s_dupacks = 0; + /* + * If our correspondent acknowledges data we haven't sent + * TCP would drop the packet after acking. We'll be a little + * more permissive + */ + if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { + sppstat.spps_rcvacktoomuch++; + si->si_ack = cb->s_smax + 1; + } + sppstat.spps_rcvackpack++; + /* + * If transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * See discussion of algorithm in tcp_input.c + */ + if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { + sppstat.spps_rttupdated++; + if (cb->s_srtt != 0) { + register short delta; + delta = cb->s_rtt - (cb->s_srtt >> 3); + if ((cb->s_srtt += delta) <= 0) + cb->s_srtt = 1; + if (delta < 0) + delta = -delta; + delta -= (cb->s_rttvar >> 2); + if ((cb->s_rttvar += delta) <= 0) + cb->s_rttvar = 1; + } else { + /* + * No rtt measurement yet + */ + cb->s_srtt = cb->s_rtt << 3; + cb->s_rttvar = cb->s_rtt << 1; + } + cb->s_rtt = 0; + cb->s_rxtshift = 0; + SPPT_RANGESET(cb->s_rxtcur, + ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, + SPPTV_MIN, SPPTV_REXMTMAX); + } + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value; + */ + if (si->si_ack == cb->s_smax + 1) { + cb->s_timer[SPPT_REXMT] = 0; + cb->s_flags |= SF_RXT; + } else if (cb->s_timer[SPPT_PERSIST] == 0) + cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg at a time). + * Otherwise open linearly (maxseg^2 / cwnd at a time). + */ + incr = CUNIT; + if (cb->s_cwnd > cb->s_ssthresh) + incr = max(incr * incr / cb->s_cwnd, 1); + cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); + /* + * Trim Acked data from output queue. + */ + while ((m = so->so_snd.sb_mb) != NULL) { + if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack)) + sbdroprecord(&so->so_snd); + else + break; + } + sowwakeup(so); + cb->s_rack = si->si_ack; +update_window: + if (SSEQ_LT(cb->s_snxt, cb->s_rack)) + cb->s_snxt = cb->s_rack; + if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && + (SSEQ_LT(cb->s_swl2, si->si_ack) || + cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { + /* keep track of pure window updates */ + if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack + && SSEQ_LT(cb->s_ralo, si->si_alo)) { + sppstat.spps_rcvwinupd++; + sppstat.spps_rcvdupack--; + } + cb->s_ralo = si->si_alo; + cb->s_swl1 = si->si_seq; + cb->s_swl2 = si->si_ack; + cb->s_swnd = (1 + si->si_alo - si->si_ack); + if (cb->s_swnd > cb->s_smxw) + cb->s_smxw = cb->s_swnd; + cb->s_flags |= SF_WIN; + } + /* + * If this packet number is higher than that which + * we have allocated refuse it, unless urgent + */ + if (SSEQ_GT(si->si_seq, cb->s_alo)) { + if (si->si_cc & SP_SP) { + sppstat.spps_rcvwinprobe++; + return (1); + } else + sppstat.spps_rcvpackafterwin++; + if (si->si_cc & SP_OB) { + if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { + ns_error(dtom(si), NS_ERR_FULLUP, 0); + return (0); + } /* else queue this packet; */ + } else { + /*register struct socket *so = cb->s_nspcb->nsp_socket; + if (so->so_state && SS_NOFDREF) { + ns_error(dtom(si), NS_ERR_NOSOCK, 0); + (void)spp_close(cb); + } else + would crash system*/ + spp_istat.notyet++; + ns_error(dtom(si), NS_ERR_FULLUP, 0); + return (0); + } + } + /* + * If this is a system packet, we don't need to + * queue it up, and won't update acknowledge # + */ + if (si->si_cc & SP_SP) { + return (1); + } + /* + * We have already seen this packet, so drop. + */ + if (SSEQ_LT(si->si_seq, cb->s_ack)) { + spp_istat.bdreas++; + sppstat.spps_rcvduppack++; + if (si->si_seq == cb->s_ack - 1) + spp_istat.lstdup++; + return (1); + } + /* + * Loop through all packets queued up to insert in + * appropriate sequence. + */ + for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { + if (si->si_seq == SI(q)->si_seq) { + sppstat.spps_rcvduppack++; + return (1); + } + if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { + sppstat.spps_rcvoopack++; + break; + } + } + insque(si, q->si_prev); + /* + * If this packet is urgent, inform process + */ + if (si->si_cc & SP_OB) { + cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; + sohasoutofband(so); + cb->s_oobflags |= SF_IOOB; + } +present: +#define SPINC sizeof(struct sphdr) + /* + * Loop through all packets queued up to update acknowledge + * number, and present all acknowledged data to user; + * If in packet interface mode, show packet headers. + */ + for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { + if (SI(q)->si_seq == cb->s_ack) { + cb->s_ack++; + m = dtom(q); + if (SI(q)->si_cc & SP_OB) { + cb->s_oobflags &= ~SF_IOOB; + if (so->so_rcv.sb_cc) + so->so_oobmark = so->so_rcv.sb_cc; + else + so->so_state |= SS_RCVATMARK; + } + q = q->si_prev; + remque(q->si_next); + wakeup = 1; + sppstat.spps_rcvpack++; +#ifdef SF_NEWCALL + if (cb->s_flags2 & SF_NEWCALL) { + struct sphdr *sp = mtod(m, struct sphdr *); + u_char dt = sp->sp_dt; + spp_newchecks[4]++; + if (dt != cb->s_rhdr.sp_dt) { + struct mbuf *mm = + m_getclr(M_DONTWAIT, MT_CONTROL); + spp_newchecks[0]++; + if (mm != NULL) { + u_short *s = + mtod(mm, u_short *); + cb->s_rhdr.sp_dt = dt; + mm->m_len = 5; /*XXX*/ + s[0] = 5; + s[1] = 1; + *(u_char *)(&s[2]) = dt; + sbappend(&so->so_rcv, mm); + } + } + if (sp->sp_cc & SP_OB) { + MCHTYPE(m, MT_OOBDATA); + spp_newchecks[1]++; + so->so_oobmark = 0; + so->so_state &= ~SS_RCVATMARK; + } + if (packetp == 0) { + m->m_data += SPINC; + m->m_len -= SPINC; + m->m_pkthdr.len -= SPINC; + } + if ((sp->sp_cc & SP_EM) || packetp) { + sbappendrecord(&so->so_rcv, m); + spp_newchecks[9]++; + } else + sbappend(&so->so_rcv, m); + } else +#endif + if (packetp) { + sbappendrecord(&so->so_rcv, m); + } else { + cb->s_rhdr = *mtod(m, struct sphdr *); + m->m_data += SPINC; + m->m_len -= SPINC; + m->m_pkthdr.len -= SPINC; + sbappend(&so->so_rcv, m); + } + } else + break; + } + if (wakeup) sorwakeup(so); + return (0); +} + +spp_ctlinput(cmd, arg) + int cmd; + caddr_t arg; +{ + struct ns_addr *na; + extern u_char nsctlerrmap[]; + extern spp_abort(), spp_quench(); + extern struct nspcb *idp_drop(); + struct ns_errp *errp; + struct nspcb *nsp; + struct sockaddr_ns *sns; + int type; + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + type = NS_ERR_UNREACH_HOST; + + switch (cmd) { + + case PRC_ROUTEDEAD: + return; + + case PRC_IFDOWN: + case PRC_HOSTDEAD: + case PRC_HOSTUNREACH: + sns = (struct sockaddr_ns *)arg; + if (sns->sns_family != AF_NS) + return; + na = &sns->sns_addr; + break; + + default: + errp = (struct ns_errp *)arg; + na = &errp->ns_err_idp.idp_dna; + type = errp->ns_err_num; + type = ntohs((u_short)type); + } + switch (type) { + + case NS_ERR_UNREACH_HOST: + ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); + break; + + case NS_ERR_TOO_BIG: + case NS_ERR_NOSOCK: + nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, + NS_WILDCARD); + if (nsp) { + if(nsp->nsp_pcb) + (void) spp_drop((struct sppcb *)nsp->nsp_pcb, + (int)nsctlerrmap[cmd]); + else + (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); + } + break; + + case NS_ERR_FULLUP: + ns_pcbnotify(na, 0, spp_quench, (long) 0); + } +} +/* + * When a source quench is received, close congestion window + * to one packet. We will gradually open it again as we proceed. + */ +spp_quench(nsp) + struct nspcb *nsp; +{ + struct sppcb *cb = nstosppcb(nsp); + + if (cb) + cb->s_cwnd = CUNIT; +} + +#ifdef notdef +int +spp_fixmtu(nsp) +register struct nspcb *nsp; +{ + register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); + register struct mbuf *m; + register struct spidp *si; + struct ns_errp *ep; + struct sockbuf *sb; + int badseq, len; + struct mbuf *firstbad, *m0; + + if (cb) { + /* + * The notification that we have sent + * too much is bad news -- we will + * have to go through queued up so far + * splitting ones which are too big and + * reassigning sequence numbers and checksums. + * we should then retransmit all packets from + * one above the offending packet to the last one + * we had sent (or our allocation) + * then the offending one so that the any queued + * data at our destination will be discarded. + */ + ep = (struct ns_errp *)nsp->nsp_notify_param; + sb = &nsp->nsp_socket->so_snd; + cb->s_mtu = ep->ns_err_param; + badseq = SI(&ep->ns_err_idp)->si_seq; + for (m = sb->sb_mb; m; m = m->m_act) { + si = mtod(m, struct spidp *); + if (si->si_seq == badseq) + break; + } + if (m == 0) return; + firstbad = m; + /*for (;;) {*/ + /* calculate length */ + for (m0 = m, len = 0; m ; m = m->m_next) + len += m->m_len; + if (len > cb->s_mtu) { + } + /* FINISH THIS + } */ + } +} +#endif + +spp_output(cb, m0) + register struct sppcb *cb; + struct mbuf *m0; +{ + struct socket *so = cb->s_nspcb->nsp_socket; + register struct mbuf *m; + register struct spidp *si = (struct spidp *) 0; + register struct sockbuf *sb = &so->so_snd; + int len = 0, win, rcv_win; + short span, off, recordp = 0; + u_short alo; + int error = 0, sendalot; +#ifdef notdef + int idle; +#endif + struct mbuf *mprev; + extern int idpcksum; + + if (m0) { + int mtu = cb->s_mtu; + int datalen; + /* + * Make sure that packet isn't too big. + */ + for (m = m0; m ; m = m->m_next) { + mprev = m; + len += m->m_len; + if (m->m_flags & M_EOR) + recordp = 1; + } + datalen = (cb->s_flags & SF_HO) ? + len - sizeof (struct sphdr) : len; + if (datalen > mtu) { + if (cb->s_flags & SF_PI) { + m_freem(m0); + return (EMSGSIZE); + } else { + int oldEM = cb->s_cc & SP_EM; + + cb->s_cc &= ~SP_EM; + while (len > mtu) { + /* + * Here we are only being called + * from usrreq(), so it is OK to + * block. + */ + m = m_copym(m0, 0, mtu, M_WAIT); + if (cb->s_flags & SF_NEWCALL) { + struct mbuf *mm = m; + spp_newchecks[7]++; + while (mm) { + mm->m_flags &= ~M_EOR; + mm = mm->m_next; + } + } + error = spp_output(cb, m); + if (error) { + cb->s_cc |= oldEM; + m_freem(m0); + return(error); + } + m_adj(m0, mtu); + len -= mtu; + } + cb->s_cc |= oldEM; + } + } + /* + * Force length even, by adding a "garbage byte" if + * necessary. + */ + if (len & 1) { + m = mprev; + if (M_TRAILINGSPACE(m) >= 1) + m->m_len++; + else { + struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); + + if (m1 == 0) { + m_freem(m0); + return (ENOBUFS); + } + m1->m_len = 1; + *(mtod(m1, u_char *)) = 0; + m->m_next = m1; + } + } + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == 0) { + m_freem(m0); + return (ENOBUFS); + } + /* + * Fill in mbuf with extended SP header + * and addresses and length put into network format. + */ + MH_ALIGN(m, sizeof (struct spidp)); + m->m_len = sizeof (struct spidp); + m->m_next = m0; + si = mtod(m, struct spidp *); + si->si_i = *cb->s_idp; + si->si_s = cb->s_shdr; + if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { + register struct sphdr *sh; + if (m0->m_len < sizeof (*sh)) { + if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { + (void) m_free(m); + m_freem(m0); + return (EINVAL); + } + m->m_next = m0; + } + sh = mtod(m0, struct sphdr *); + si->si_dt = sh->sp_dt; + si->si_cc |= sh->sp_cc & SP_EM; + m0->m_len -= sizeof (*sh); + m0->m_data += sizeof (*sh); + len -= sizeof (*sh); + } + len += sizeof(*si); + if ((cb->s_flags2 & SF_NEWCALL) && recordp) { + si->si_cc |= SP_EM; + spp_newchecks[8]++; + } + if (cb->s_oobflags & SF_SOOB) { + /* + * Per jqj@cornell: + * make sure OB packets convey exactly 1 byte. + * If the packet is 1 byte or larger, we + * have already guaranted there to be at least + * one garbage byte for the checksum, and + * extra bytes shouldn't hurt! + */ + if (len > sizeof(*si)) { + si->si_cc |= SP_OB; + len = (1 + sizeof(*si)); + } + } + si->si_len = htons((u_short)len); + m->m_pkthdr.len = ((len - 1) | 1) + 1; + /* + * queue stuff up for output + */ + sbappendrecord(sb, m); + cb->s_seq++; + } +#ifdef notdef + idle = (cb->s_smax == (cb->s_rack - 1)); +#endif +again: + sendalot = 0; + off = cb->s_snxt - cb->s_rack; + win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)); + + /* + * If in persist timeout with window of 0, send a probe. + * Otherwise, if window is small but nonzero + * and timer expired, send what we can and go into + * transmit state. + */ + if (cb->s_force == 1 + SPPT_PERSIST) { + if (win != 0) { + cb->s_timer[SPPT_PERSIST] = 0; + cb->s_rxtshift = 0; + } + } + span = cb->s_seq - cb->s_rack; + len = min(span, win) - off; + + if (len < 0) { + /* + * Window shrank after we went into it. + * If window shrank to 0, cancel pending + * restransmission and pull s_snxt back + * to (closed) window. We will enter persist + * state below. If the widndow didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + cb->s_timer[SPPT_REXMT] = 0; + cb->s_snxt = cb->s_rack; + } + } + if (len > 1) + sendalot = 1; + rcv_win = sbspace(&so->so_rcv); + + /* + * Send if we owe peer an ACK. + */ + if (cb->s_oobflags & SF_SOOB) { + /* + * must transmit this out of band packet + */ + cb->s_oobflags &= ~ SF_SOOB; + sendalot = 1; + sppstat.spps_sndurg++; + goto found; + } + if (cb->s_flags & SF_ACKNOW) + goto send; + if (cb->s_state < TCPS_ESTABLISHED) + goto send; + /* + * Silly window can't happen in spp. + * Code from tcp deleted. + */ + if (len) + goto send; + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input.) If the difference is at least two + * packets or at least 35% of the mximum possible window, + * then want to send a window update to peer. + */ + if (rcv_win > 0) { + u_short delta = 1 + cb->s_alo - cb->s_ack; + int adv = rcv_win - (delta * cb->s_mtu); + + if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || + (100 * adv / so->so_rcv.sb_hiwat >= 35)) { + sppstat.spps_sndwinup++; + cb->s_flags |= SF_ACKNOW; + goto send; + } + + } + /* + * Many comments from tcp_output.c are appropriate here + * including . . . + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise send a probe. + */ + if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 && + cb->s_timer[SPPT_PERSIST] == 0) { + cb->s_rxtshift = 0; + spp_setpersist(cb); + } + /* + * No reason to send a packet, just return. + */ + cb->s_outx = 1; + return (0); + +send: + /* + * Find requested packet. + */ + si = 0; + if (len > 0) { + cb->s_want = cb->s_snxt; + for (m = sb->sb_mb; m; m = m->m_act) { + si = mtod(m, struct spidp *); + if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) + break; + } + found: + if (si) { + if (si->si_seq == cb->s_snxt) + cb->s_snxt++; + else + sppstat.spps_sndvoid++, si = 0; + } + } + /* + * update window + */ + if (rcv_win < 0) + rcv_win = 0; + alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); + if (SSEQ_LT(alo, cb->s_alo)) + alo = cb->s_alo; + + if (si) { + /* + * must make a copy of this packet for + * idp_output to monkey with + */ + m = m_copy(dtom(si), 0, (int)M_COPYALL); + if (m == NULL) { + return (ENOBUFS); + } + si = mtod(m, struct spidp *); + if (SSEQ_LT(si->si_seq, cb->s_smax)) + sppstat.spps_sndrexmitpack++; + else + sppstat.spps_sndpack++; + } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { + /* + * Must send an acknowledgement or a probe + */ + if (cb->s_force) + sppstat.spps_sndprobe++; + if (cb->s_flags & SF_ACKNOW) + sppstat.spps_sndacks++; + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == 0) + return (ENOBUFS); + /* + * Fill in mbuf with extended SP header + * and addresses and length put into network format. + */ + MH_ALIGN(m, sizeof (struct spidp)); + m->m_len = sizeof (*si); + m->m_pkthdr.len = sizeof (*si); + si = mtod(m, struct spidp *); + si->si_i = *cb->s_idp; + si->si_s = cb->s_shdr; + si->si_seq = cb->s_smax + 1; + si->si_len = htons(sizeof (*si)); + si->si_cc |= SP_SP; + } else { + cb->s_outx = 3; + if (so->so_options & SO_DEBUG || traceallspps) + spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + return (0); + } + /* + * Stuff checksum and output datagram. + */ + if ((si->si_cc & SP_SP) == 0) { + if (cb->s_force != (1 + SPPT_PERSIST) || + cb->s_timer[SPPT_PERSIST] == 0) { + /* + * If this is a new packet and we are not currently + * timing anything, time this one. + */ + if (SSEQ_LT(cb->s_smax, si->si_seq)) { + cb->s_smax = si->si_seq; + if (cb->s_rtt == 0) { + sppstat.spps_segstimed++; + cb->s_rtseq = si->si_seq; + cb->s_rtt = 1; + } + } + /* + * Set rexmt timer if not currently set, + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (cb->s_timer[SPPT_REXMT] == 0 && + cb->s_snxt != cb->s_rack) { + cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; + if (cb->s_timer[SPPT_PERSIST]) { + cb->s_timer[SPPT_PERSIST] = 0; + cb->s_rxtshift = 0; + } + } + } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { + cb->s_smax = si->si_seq; + } + } else if (cb->s_state < TCPS_ESTABLISHED) { + if (cb->s_rtt == 0) + cb->s_rtt = 1; /* Time initial handshake */ + if (cb->s_timer[SPPT_REXMT] == 0) + cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; + } + { + /* + * Do not request acks when we ack their data packets or + * when we do a gratuitous window update. + */ + if (((si->si_cc & SP_SP) == 0) || cb->s_force) + si->si_cc |= SP_SA; + si->si_seq = htons(si->si_seq); + si->si_alo = htons(alo); + si->si_ack = htons(cb->s_ack); + + if (idpcksum) { + si->si_sum = 0; + len = ntohs(si->si_len); + if (len & 1) + len++; + si->si_sum = ns_cksum(m, len); + } else + si->si_sum = 0xffff; + + cb->s_outx = 4; + if (so->so_options & SO_DEBUG || traceallspps) + spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + + if (so->so_options & SO_DONTROUTE) + error = ns_output(m, (struct route *)0, NS_ROUTETOIF); + else + error = ns_output(m, &cb->s_nspcb->nsp_route, 0); + } + if (error) { + return (error); + } + sppstat.spps_sndtotal++; + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertized window. + * Any pending ACK has now been sent. + */ + cb->s_force = 0; + cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); + if (SSEQ_GT(alo, cb->s_alo)) + cb->s_alo = alo; + if (sendalot) + goto again; + cb->s_outx = 5; + return (0); +} + +int spp_do_persist_panics = 0; + +spp_setpersist(cb) + register struct sppcb *cb; +{ + register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; + extern int spp_backoff[]; + + if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics) + panic("spp_output REXMT"); + /* + * Start/restart persistance timer. + */ + SPPT_RANGESET(cb->s_timer[SPPT_PERSIST], + t*spp_backoff[cb->s_rxtshift], + SPPTV_PERSMIN, SPPTV_PERSMAX); + if (cb->s_rxtshift < SPP_MAXRXTSHIFT) + cb->s_rxtshift++; +} +/*ARGSUSED*/ +spp_ctloutput(req, so, level, name, value) + int req; + struct socket *so; + int name; + struct mbuf **value; +{ + register struct mbuf *m; + struct nspcb *nsp = sotonspcb(so); + register struct sppcb *cb; + int mask, error = 0; + + if (level != NSPROTO_SPP) { + /* This will have to be changed when we do more general + stacking of protocols */ + return (idp_ctloutput(req, so, level, name, value)); + } + if (nsp == NULL) { + error = EINVAL; + goto release; + } else + cb = nstosppcb(nsp); + + switch (req) { + + case PRCO_GETOPT: + if (value == NULL) + return (EINVAL); + m = m_get(M_DONTWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + switch (name) { + + case SO_HEADERS_ON_INPUT: + mask = SF_HI; + goto get_flags; + + case SO_HEADERS_ON_OUTPUT: + mask = SF_HO; + get_flags: + m->m_len = sizeof(short); + *mtod(m, short *) = cb->s_flags & mask; + break; + + case SO_MTU: + m->m_len = sizeof(u_short); + *mtod(m, short *) = cb->s_mtu; + break; + + case SO_LAST_HEADER: + m->m_len = sizeof(struct sphdr); + *mtod(m, struct sphdr *) = cb->s_rhdr; + break; + + case SO_DEFAULT_HEADERS: + m->m_len = sizeof(struct spidp); + *mtod(m, struct sphdr *) = cb->s_shdr; + break; + + default: + error = EINVAL; + } + *value = m; + break; + + case PRCO_SETOPT: + if (value == 0 || *value == 0) { + error = EINVAL; + break; + } + switch (name) { + int *ok; + + case SO_HEADERS_ON_INPUT: + mask = SF_HI; + goto set_head; + + case SO_HEADERS_ON_OUTPUT: + mask = SF_HO; + set_head: + if (cb->s_flags & SF_PI) { + ok = mtod(*value, int *); + if (*ok) + cb->s_flags |= mask; + else + cb->s_flags &= ~mask; + } else error = EINVAL; + break; + + case SO_MTU: + cb->s_mtu = *(mtod(*value, u_short *)); + break; + +#ifdef SF_NEWCALL + case SO_NEWCALL: + ok = mtod(*value, int *); + if (*ok) { + cb->s_flags2 |= SF_NEWCALL; + spp_newchecks[5]++; + } else { + cb->s_flags2 &= ~SF_NEWCALL; + spp_newchecks[6]++; + } + break; +#endif + + case SO_DEFAULT_HEADERS: + { + register struct sphdr *sp + = mtod(*value, struct sphdr *); + cb->s_dt = sp->sp_dt; + cb->s_cc = sp->sp_cc & SP_EM; + } + break; + + default: + error = EINVAL; + } + m_freem(*value); + break; + } + release: + return (error); +} + +/*ARGSUSED*/ +spp_usrreq(so, req, m, nam, controlp) + struct socket *so; + int req; + struct mbuf *m, *nam, *controlp; +{ + struct nspcb *nsp = sotonspcb(so); + register struct sppcb *cb; + int s = splnet(); + int error = 0, ostate; + struct mbuf *mm; + register struct sockbuf *sb; + + if (req == PRU_CONTROL) + return (ns_control(so, (int)m, (caddr_t)nam, + (struct ifnet *)controlp)); + if (nsp == NULL) { + if (req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + } else + cb = nstosppcb(nsp); + + ostate = cb ? cb->s_state : 0; + + switch (req) { + + case PRU_ATTACH: + if (nsp != NULL) { + error = EISCONN; + break; + } + error = ns_pcballoc(so, &nspcb); + if (error) + break; + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, (u_long) 3072, (u_long) 3072); + if (error) + break; + } + nsp = sotonspcb(so); + + mm = m_getclr(M_DONTWAIT, MT_PCB); + sb = &so->so_snd; + + if (mm == NULL) { + error = ENOBUFS; + break; + } + cb = mtod(mm, struct sppcb *); + mm = m_getclr(M_DONTWAIT, MT_HEADER); + if (mm == NULL) { + (void) m_free(dtom(m)); + error = ENOBUFS; + break; + } + cb->s_idp = mtod(mm, struct idp *); + cb->s_state = TCPS_LISTEN; + cb->s_smax = -1; + cb->s_swl1 = -1; + cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; + cb->s_nspcb = nsp; + cb->s_mtu = 576 - sizeof (struct spidp); + cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; + cb->s_ssthresh = cb->s_cwnd; + cb->s_cwmx = sbspace(sb) * CUNIT / + (2 * sizeof (struct spidp)); + /* Above is recomputed when connecting to account + for changed buffering or mtu's */ + cb->s_rtt = SPPTV_SRTTBASE; + cb->s_rttvar = SPPTV_SRTTDFLT << 2; + SPPT_RANGESET(cb->s_rxtcur, + ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1, + SPPTV_MIN, SPPTV_REXMTMAX); + nsp->nsp_pcb = (caddr_t) cb; + break; + + case PRU_DETACH: + if (nsp == NULL) { + error = ENOTCONN; + break; + } + if (cb->s_state > TCPS_LISTEN) + cb = spp_disconnect(cb); + else + cb = spp_close(cb); + break; + + case PRU_BIND: + error = ns_pcbbind(nsp, nam); + break; + + case PRU_LISTEN: + if (nsp->nsp_lport == 0) + error = ns_pcbbind(nsp, (struct mbuf *)0); + if (error == 0) + cb->s_state = TCPS_LISTEN; + break; + + /* + * Initiate connection to peer. + * Enter SYN_SENT state, and mark socket as connecting. + * Start keep-alive timer, setup prototype header, + * Send initial system packet requesting connection. + */ + case PRU_CONNECT: + if (nsp->nsp_lport == 0) { + error = ns_pcbbind(nsp, (struct mbuf *)0); + if (error) + break; + } + error = ns_pcbconnect(nsp, nam); + if (error) + break; + soisconnecting(so); + sppstat.spps_connattempt++; + cb->s_state = TCPS_SYN_SENT; + cb->s_did = 0; + spp_template(cb); + cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + cb->s_force = 1 + SPPTV_KEEP; + /* + * Other party is required to respond to + * the port I send from, but he is not + * required to answer from where I am sending to, + * so allow wildcarding. + * original port I am sending to is still saved in + * cb->s_dport. + */ + nsp->nsp_fport = 0; + error = spp_output(cb, (struct mbuf *) 0); + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + /* + * We may decide later to implement connection closing + * handshaking at the spp level optionally. + * here is the hook to do it: + */ + case PRU_DISCONNECT: + cb = spp_disconnect(cb); + break; + + /* + * Accept a connection. Essentially all the work is + * done at higher levels; just return the address + * of the peer, storing through addr. + */ + case PRU_ACCEPT: { + struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); + + nam->m_len = sizeof (struct sockaddr_ns); + sns->sns_family = AF_NS; + sns->sns_addr = nsp->nsp_faddr; + break; + } + + case PRU_SHUTDOWN: + socantsendmore(so); + cb = spp_usrclosed(cb); + if (cb) + error = spp_output(cb, (struct mbuf *) 0); + break; + + /* + * After a receive, possibly send acknowledgment + * updating allocation. + */ + case PRU_RCVD: + cb->s_flags |= SF_RVD; + (void) spp_output(cb, (struct mbuf *) 0); + cb->s_flags &= ~SF_RVD; + break; + + case PRU_ABORT: + (void) spp_drop(cb, ECONNABORTED); + break; + + case PRU_SENSE: + case PRU_CONTROL: + m = NULL; + error = EOPNOTSUPP; + break; + + case PRU_RCVOOB: + if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || + (so->so_state & SS_RCVATMARK)) { + m->m_len = 1; + *mtod(m, caddr_t) = cb->s_iobc; + break; + } + error = EINVAL; + break; + + case PRU_SENDOOB: + if (sbspace(&so->so_snd) < -512) { + error = ENOBUFS; + break; + } + cb->s_oobflags |= SF_SOOB; + /* fall into */ + case PRU_SEND: + if (controlp) { + u_short *p = mtod(controlp, u_short *); + spp_newchecks[2]++; + if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ + cb->s_shdr.sp_dt = *(u_char *)(&p[2]); + spp_newchecks[3]++; + } + m_freem(controlp); + } + controlp = NULL; + error = spp_output(cb, m); + m = NULL; + break; + + case PRU_SOCKADDR: + ns_setsockaddr(nsp, nam); + break; + + case PRU_PEERADDR: + ns_setpeeraddr(nsp, nam); + break; + + case PRU_SLOWTIMO: + cb = spp_timers(cb, (int)nam); + req |= ((int)nam) << 8; + break; + + case PRU_FASTTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + default: + panic("sp_usrreq"); + } + if (cb && (so->so_options & SO_DEBUG || traceallspps)) + spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); +release: + if (controlp != NULL) + m_freem(controlp); + if (m != NULL) + m_freem(m); + splx(s); + return (error); +} + +spp_usrreq_sp(so, req, m, nam, controlp) + struct socket *so; + int req; + struct mbuf *m, *nam, *controlp; +{ + int error = spp_usrreq(so, req, m, nam, controlp); + + if (req == PRU_ATTACH && error == 0) { + struct nspcb *nsp = sotonspcb(so); + ((struct sppcb *)nsp->nsp_pcb)->s_flags |= + (SF_HI | SF_HO | SF_PI); + } + return (error); +} + +/* + * Create template to be used to send spp packets on a connection. + * Called after host entry created, fills + * in a skeletal spp header (choosing connection id), + * minimizing the amount of work necessary when the connection is used. + */ +spp_template(cb) + register struct sppcb *cb; +{ + register struct nspcb *nsp = cb->s_nspcb; + register struct idp *idp = cb->s_idp; + register struct sockbuf *sb = &(nsp->nsp_socket->so_snd); + + idp->idp_pt = NSPROTO_SPP; + idp->idp_sna = nsp->nsp_laddr; + idp->idp_dna = nsp->nsp_faddr; + cb->s_sid = htons(spp_iss); + spp_iss += SPP_ISSINCR/2; + cb->s_alo = 1; + cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; + cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement + of large packets */ + cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp)); + cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); + /* But allow for lots of little packets as well */ +} + +/* + * Close a SPIP control block: + * discard spp control block itself + * discard ns protocol control block + * wake up any sleepers + */ +struct sppcb * +spp_close(cb) + register struct sppcb *cb; +{ + register struct spidp_q *s; + struct nspcb *nsp = cb->s_nspcb; + struct socket *so = nsp->nsp_socket; + register struct mbuf *m; + + s = cb->s_q.si_next; + while (s != &(cb->s_q)) { + s = s->si_next; + m = dtom(s->si_prev); + remque(s->si_prev); + m_freem(m); + } + (void) m_free(dtom(cb->s_idp)); + (void) m_free(dtom(cb)); + nsp->nsp_pcb = 0; + soisdisconnected(so); + ns_pcbdetach(nsp); + sppstat.spps_closed++; + return ((struct sppcb *)0); +} +/* + * Someday we may do level 3 handshaking + * to close a connection or send a xerox style error. + * For now, just close. + */ +struct sppcb * +spp_usrclosed(cb) + register struct sppcb *cb; +{ + return (spp_close(cb)); +} +struct sppcb * +spp_disconnect(cb) + register struct sppcb *cb; +{ + return (spp_close(cb)); +} +/* + * Drop connection, reporting + * the specified error. + */ +struct sppcb * +spp_drop(cb, errno) + register struct sppcb *cb; + int errno; +{ + struct socket *so = cb->s_nspcb->nsp_socket; + + /* + * someday, in the xerox world + * we will generate error protocol packets + * announcing that the socket has gone away. + */ + if (TCPS_HAVERCVDSYN(cb->s_state)) { + sppstat.spps_drops++; + cb->s_state = TCPS_CLOSED; + /*(void) tcp_output(cb);*/ + } else + sppstat.spps_conndrops++; + so->so_error = errno; + return (spp_close(cb)); +} + +spp_abort(nsp) + struct nspcb *nsp; +{ + + (void) spp_close((struct sppcb *)nsp->nsp_pcb); +} + +int spp_backoff[SPP_MAXRXTSHIFT+1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; +/* + * Fast timeout routine for processing delayed acks + */ +spp_fasttimo() +{ + register struct nspcb *nsp; + register struct sppcb *cb; + int s = splnet(); + + nsp = nspcb.nsp_next; + if (nsp) + for (; nsp != &nspcb; nsp = nsp->nsp_next) + if ((cb = (struct sppcb *)nsp->nsp_pcb) && + (cb->s_flags & SF_DELACK)) { + cb->s_flags &= ~SF_DELACK; + cb->s_flags |= SF_ACKNOW; + sppstat.spps_delack++; + (void) spp_output(cb, (struct mbuf *) 0); + } + splx(s); +} + +/* + * spp protocol timeout routine called every 500 ms. + * Updates the timers in all active pcb's and + * causes finite state machine actions if timers expire. + */ +spp_slowtimo() +{ + register struct nspcb *ip, *ipnxt; + register struct sppcb *cb; + int s = splnet(); + register int i; + + /* + * Search through tcb's and update active timers. + */ + ip = nspcb.nsp_next; + if (ip == 0) { + splx(s); + return; + } + while (ip != &nspcb) { + cb = nstosppcb(ip); + ipnxt = ip->nsp_next; + if (cb == 0) + goto tpgone; + for (i = 0; i < SPPT_NTIMERS; i++) { + if (cb->s_timer[i] && --cb->s_timer[i] == 0) { + (void) spp_usrreq(cb->s_nspcb->nsp_socket, + PRU_SLOWTIMO, (struct mbuf *)0, + (struct mbuf *)i, (struct mbuf *)0, + (struct mbuf *)0); + if (ipnxt->nsp_prev != ip) + goto tpgone; + } + } + cb->s_idle++; + if (cb->s_rtt) + cb->s_rtt++; +tpgone: + ip = ipnxt; + } + spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ + splx(s); +} +/* + * SPP timer processing. + */ +struct sppcb * +spp_timers(cb, timer) + register struct sppcb *cb; + int timer; +{ + long rexmt; + int win; + + cb->s_force = 1 + timer; + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. TCP deletes connection + * control block. + */ + case SPPT_2MSL: + printf("spp: SPPT_2MSL went off for no reason\n"); + cb->s_timer[timer] = 0; + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one packet. + */ + case SPPT_REXMT: + if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) { + cb->s_rxtshift = SPP_MAXRXTSHIFT; + sppstat.spps_timeoutdrop++; + cb = spp_drop(cb, ETIMEDOUT); + break; + } + sppstat.spps_rexmttimeo++; + rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; + rexmt *= spp_backoff[cb->s_rxtshift]; + SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX); + cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; + /* + * If we have backed off fairly far, our srtt + * estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) { + cb->s_rttvar += (cb->s_srtt >> 2); + cb->s_srtt = 0; + } + cb->s_snxt = cb->s_rack; + /* + * If timing a packet, stop the timer. + */ + cb->s_rtt = 0; + /* + * See very long discussion in tcp_timer.c about congestion + * window and sstrhesh + */ + win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; + if (win < 2) + win = 2; + cb->s_cwnd = CUNIT; + cb->s_ssthresh = win * CUNIT; + (void) spp_output(cb, (struct mbuf *) 0); + break; + + /* + * Persistance timer into zero window. + * Force a probe to be sent. + */ + case SPPT_PERSIST: + sppstat.spps_persisttimeo++; + spp_setpersist(cb); + (void) spp_output(cb, (struct mbuf *) 0); + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case SPPT_KEEP: + sppstat.spps_keeptimeo++; + if (cb->s_state < TCPS_ESTABLISHED) + goto dropit; + if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { + if (cb->s_idle >= SPPTV_MAXIDLE) + goto dropit; + sppstat.spps_keepprobe++; + (void) spp_output(cb, (struct mbuf *) 0); + } else + cb->s_idle = 0; + cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + break; + dropit: + sppstat.spps_keepdrops++; + cb = spp_drop(cb, ETIMEDOUT); + break; + } + return (cb); +} +#ifndef lint +int SppcbSize = sizeof (struct sppcb); +int NspcbSize = sizeof (struct nspcb); +#endif /* lint */ diff --git a/sys/netns/spp_var.h b/sys/netns/spp_var.h new file mode 100644 index 000000000000..8b630d1c8ab6 --- /dev/null +++ b/sys/netns/spp_var.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1984, 1985, 1986, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spp_var.h 8.1 (Berkeley) 6/10/93 + * $Id: spp_var.h,v 1.3 1994/08/21 06:22:12 paul Exp $ + */ + +#ifndef _NETNS_SPP_VAR_H_ +#define _NETNS_SPP_VAR_H_ + +/* + * Sp control block, one per connection + */ +struct sppcb { + struct spidp_q s_q; /* queue for out-of-order receipt */ + struct nspcb *s_nspcb; /* backpointer to internet pcb */ + u_char s_state; + u_char s_flags; +#define SF_ACKNOW 0x01 /* Ack peer immediately */ +#define SF_DELACK 0x02 /* Ack, but try to delay it */ +#define SF_HI 0x04 /* Show headers on input */ +#define SF_HO 0x08 /* Show headers on output */ +#define SF_PI 0x10 /* Packet (datagram) interface */ +#define SF_WIN 0x20 /* Window info changed */ +#define SF_RXT 0x40 /* Rxt info changed */ +#define SF_RVD 0x80 /* Calling from read usrreq routine */ + u_short s_mtu; /* Max packet size for this stream */ +/* use sequence fields in headers to store sequence numbers for this + connection */ + struct idp *s_idp; + struct sphdr s_shdr; /* prototype header to transmit */ +#define s_cc s_shdr.sp_cc /* connection control (for EM bit) */ +#define s_dt s_shdr.sp_dt /* datastream type */ +#define s_sid s_shdr.sp_sid /* source connection identifier */ +#define s_did s_shdr.sp_did /* destination connection identifier */ +#define s_seq s_shdr.sp_seq /* sequence number */ +#define s_ack s_shdr.sp_ack /* acknowledge number */ +#define s_alo s_shdr.sp_alo /* allocation number */ +#define s_dport s_idp->idp_dna.x_port /* where we are sending */ + struct sphdr s_rhdr; /* last received header (in effect!)*/ + u_short s_rack; /* their acknowledge number */ + u_short s_ralo; /* their allocation number */ + u_short s_smax; /* highest packet # we have sent */ + u_short s_snxt; /* which packet to send next */ + +/* congestion control */ +#define CUNIT 1024 /* scaling for ... */ + int s_cwnd; /* Congestion-controlled window */ + /* in packets * CUNIT */ + short s_swnd; /* == tcp snd_wnd, in packets */ + short s_smxw; /* == tcp max_sndwnd */ + /* difference of two spp_seq's can be + no bigger than a short */ + u_short s_swl1; /* == tcp snd_wl1 */ + u_short s_swl2; /* == tcp snd_wl2 */ + int s_cwmx; /* max allowable cwnd */ + int s_ssthresh; /* s_cwnd size threshhold for + * slow start exponential-to- + * linear switch */ +/* transmit timing stuff + * srtt and rttvar are stored as fixed point, for convenience in smoothing. + * srtt has 3 bits to the right of the binary point, rttvar has 2. + */ + short s_idle; /* time idle */ + short s_timer[SPPT_NTIMERS]; /* timers */ + short s_rxtshift; /* log(2) of rexmt exp. backoff */ + short s_rxtcur; /* current retransmit value */ + u_short s_rtseq; /* packet being timed */ + short s_rtt; /* timer for round trips */ + short s_srtt; /* averaged timer */ + short s_rttvar; /* variance in round trip time */ + char s_force; /* which timer expired */ + char s_dupacks; /* counter to intuit xmt loss */ + +/* out of band data */ + char s_oobflags; +#define SF_SOOB 0x08 /* sending out of band data */ +#define SF_IOOB 0x10 /* receiving out of band data */ + char s_iobc; /* input characters */ +/* debug stuff */ + u_short s_want; /* Last candidate for sending */ + char s_outx; /* exit taken from spp_output */ + char s_inx; /* exit taken from spp_input */ + u_short s_flags2; /* more flags for testing */ +#define SF_NEWCALL 0x100 /* for new_recvmsg */ +#define SO_NEWCALL 10 /* for new_recvmsg */ +}; + +#define nstosppcb(np) ((struct sppcb *)(np)->nsp_pcb) +#define sotosppcb(so) (nstosppcb(sotonspcb(so))) + +struct sppstat { + long spps_connattempt; /* connections initiated */ + long spps_accepts; /* connections accepted */ + long spps_connects; /* connections established */ + long spps_drops; /* connections dropped */ + long spps_conndrops; /* embryonic connections dropped */ + long spps_closed; /* conn. closed (includes drops) */ + long spps_segstimed; /* segs where we tried to get rtt */ + long spps_rttupdated; /* times we succeeded */ + long spps_delack; /* delayed acks sent */ + long spps_timeoutdrop; /* conn. dropped in rxmt timeout */ + long spps_rexmttimeo; /* retransmit timeouts */ + long spps_persisttimeo; /* persist timeouts */ + long spps_keeptimeo; /* keepalive timeouts */ + long spps_keepprobe; /* keepalive probes sent */ + long spps_keepdrops; /* connections dropped in keepalive */ + + long spps_sndtotal; /* total packets sent */ + long spps_sndpack; /* data packets sent */ + long spps_sndbyte; /* data bytes sent */ + long spps_sndrexmitpack; /* data packets retransmitted */ + long spps_sndrexmitbyte; /* data bytes retransmitted */ + long spps_sndacks; /* ack-only packets sent */ + long spps_sndprobe; /* window probes sent */ + long spps_sndurg; /* packets sent with URG only */ + long spps_sndwinup; /* window update-only packets sent */ + long spps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + long spps_sndvoid; /* couldn't find requested packet*/ + + long spps_rcvtotal; /* total packets received */ + long spps_rcvpack; /* packets received in sequence */ + long spps_rcvbyte; /* bytes received in sequence */ + long spps_rcvbadsum; /* packets received with ccksum errs */ + long spps_rcvbadoff; /* packets received with bad offset */ + long spps_rcvshort; /* packets received too short */ + long spps_rcvduppack; /* duplicate-only packets received */ + long spps_rcvdupbyte; /* duplicate-only bytes received */ + long spps_rcvpartduppack; /* packets with some duplicate data */ + long spps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + long spps_rcvoopack; /* out-of-order packets received */ + long spps_rcvoobyte; /* out-of-order bytes received */ + long spps_rcvpackafterwin; /* packets with data after window */ + long spps_rcvbyteafterwin; /* bytes rcvd after window */ + long spps_rcvafterclose; /* packets rcvd after "close" */ + long spps_rcvwinprobe; /* rcvd window probe packets */ + long spps_rcvdupack; /* rcvd duplicate acks */ + long spps_rcvacktoomuch; /* rcvd acks for unsent data */ + long spps_rcvackpack; /* rcvd ack packets */ + long spps_rcvackbyte; /* bytes acked by rcvd acks */ + long spps_rcvwinupd; /* rcvd window update packets */ +}; +struct spp_istat { + short hdrops; + short badsum; + short badlen; + short slotim; + short fastim; + short nonucn; + short noconn; + short notme; + short wrncon; + short bdreas; + short gonawy; + short notyet; + short lstdup; + struct sppstat newstats; +}; + +#ifdef KERNEL +struct spp_istat spp_istat; + +/* Following was struct sppstat sppstat; */ +#ifndef sppstat +#define sppstat spp_istat.newstats +#endif + +u_short spp_iss; +extern struct sppcb *spp_close(), *spp_disconnect(), + *spp_usrclosed(), *spp_timers(), *spp_drop(); +#endif + +#define SPP_ISSINCR 128 +/* + * SPP sequence numbers are 16 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#ifdef sun +short xnsCbug; +#define SSEQ_LT(a,b) ((xnsCbug = (short)((a)-(b))) < 0) +#define SSEQ_LEQ(a,b) ((xnsCbug = (short)((a)-(b))) <= 0) +#define SSEQ_GT(a,b) ((xnsCbug = (short)((a)-(b))) > 0) +#define SSEQ_GEQ(a,b) ((xnsCbug = (short)((a)-(b))) >= 0) +#else +#define SSEQ_LT(a,b) (((short)((a)-(b))) < 0) +#define SSEQ_LEQ(a,b) (((short)((a)-(b))) <= 0) +#define SSEQ_GT(a,b) (((short)((a)-(b))) > 0) +#define SSEQ_GEQ(a,b) (((short)((a)-(b))) >= 0) +#endif + +#endif |