123202Smckusick /* 2*33371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3*33371Ssklower * All rights reserved. 423202Smckusick * 5*33371Ssklower * Redistribution and use in source and binary forms are permitted 6*33371Ssklower * provided that this notice is preserved and that due credit is given 7*33371Ssklower * to the University of California at Berkeley. The name of the University 8*33371Ssklower * may not be used to endorse or promote products derived from this 9*33371Ssklower * software without specific prior written permission. This software 10*33371Ssklower * is provided ``as is'' without express or implied warranty. 11*33371Ssklower * 12*33371Ssklower * @(#)idp_usrreq.c 7.2 (Berkeley) 01/20/88 1323202Smckusick */ 1421479Ssklower 1521479Ssklower #include "param.h" 1621479Ssklower #include "dir.h" 1721479Ssklower #include "user.h" 1821479Ssklower #include "mbuf.h" 1921479Ssklower #include "protosw.h" 2021479Ssklower #include "socket.h" 2121479Ssklower #include "socketvar.h" 2221479Ssklower #include "errno.h" 2321479Ssklower #include "stat.h" 2421479Ssklower 2521479Ssklower #include "../net/if.h" 2621479Ssklower #include "../net/route.h" 2721479Ssklower 2821479Ssklower #include "ns.h" 2921479Ssklower #include "ns_pcb.h" 3024611Ssklower #include "ns_if.h" 3121479Ssklower #include "idp.h" 3221479Ssklower #include "idp_var.h" 3321479Ssklower #include "ns_error.h" 3421479Ssklower 3521479Ssklower /* 3621479Ssklower * IDP protocol implementation. 3721479Ssklower */ 3821479Ssklower 3921479Ssklower struct sockaddr_ns idp_ns = { AF_NS }; 4021479Ssklower 4123977Ssklower /* 4223977Ssklower * This may also be called for raw listeners. 4323977Ssklower */ 4424611Ssklower idp_input(m, nsp, ifp) 4521479Ssklower struct mbuf *m; 4621479Ssklower register struct nspcb *nsp; 4724611Ssklower struct ifnet *ifp; 4821479Ssklower { 4921479Ssklower register struct idp *idp = mtod(m, struct idp *); 5021479Ssklower 5124611Ssklower if (nsp==0) 5224049Ssklower panic("No nspcb"); 5321479Ssklower /* 5421479Ssklower * Construct sockaddr format source address. 5521479Ssklower * Stuff source address and datagram in user buffer. 5621479Ssklower */ 5721479Ssklower idp_ns.sns_addr = idp->idp_sna; 5826055Ssklower if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { 5924611Ssklower register struct ifaddr *ia; 6024611Ssklower 6124685Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 6224611Ssklower if (ia->ifa_addr.sa_family == AF_NS) { 6324611Ssklower idp_ns.sns_addr.x_net = 6424611Ssklower IA_SNS(ia)->sns_addr.x_net; 6524611Ssklower break; 6624611Ssklower } 6724611Ssklower } 6824611Ssklower } 6921479Ssklower nsp->nsp_rpt = idp->idp_pt; 7021479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 7121479Ssklower m->m_len -= sizeof (struct idp); 7221479Ssklower m->m_off += sizeof (struct idp); 7321479Ssklower } 7421479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 7521479Ssklower m, (struct mbuf *)0) == 0) 7621479Ssklower goto bad; 7721479Ssklower sorwakeup(nsp->nsp_socket); 7821479Ssklower return; 7921479Ssklower bad: 8021479Ssklower m_freem(m); 8121479Ssklower } 8221479Ssklower 8321479Ssklower idp_abort(nsp) 8421479Ssklower struct nspcb *nsp; 8521479Ssklower { 8621479Ssklower struct socket *so = nsp->nsp_socket; 8721479Ssklower 8821479Ssklower ns_pcbdisconnect(nsp); 8921479Ssklower soisdisconnected(so); 9021479Ssklower } 9123977Ssklower /* 9223977Ssklower * Drop connection, reporting 9323977Ssklower * the specified error. 9423977Ssklower */ 9523977Ssklower struct nspcb * 9623977Ssklower idp_drop(nsp, errno) 9723977Ssklower register struct nspcb *nsp; 9823977Ssklower int errno; 9923977Ssklower { 10023977Ssklower struct socket *so = nsp->nsp_socket; 10121479Ssklower 10223977Ssklower /* 10323977Ssklower * someday, in the xerox world 10423977Ssklower * we will generate error protocol packets 10523977Ssklower * announcing that the socket has gone away. 10623977Ssklower */ 10723977Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 10823977Ssklower tp->t_state = TCPS_CLOSED; 10923977Ssklower (void) tcp_output(tp); 11023977Ssklower }*/ 11123977Ssklower so->so_error = errno; 11223977Ssklower ns_pcbdisconnect(nsp); 11323977Ssklower soisdisconnected(so); 11423977Ssklower } 11523977Ssklower 11625042Ssklower int noIdpRoute; 11721479Ssklower idp_output(nsp, m0) 11821479Ssklower struct nspcb *nsp; 11921479Ssklower struct mbuf *m0; 12021479Ssklower { 12121479Ssklower register struct mbuf *m; 12221479Ssklower register struct idp *idp; 12321479Ssklower register struct socket *so; 12421479Ssklower register int len = 0; 12521479Ssklower register struct route *ro; 12621479Ssklower struct mbuf *mprev; 12721479Ssklower extern int idpcksum; 12821479Ssklower 12921479Ssklower /* 13021479Ssklower * Calculate data length. 13121479Ssklower */ 13221479Ssklower for (m = m0; m; m = m->m_next) { 13321479Ssklower mprev = m; 13421479Ssklower len += m->m_len; 13521479Ssklower } 13621479Ssklower /* 13721479Ssklower * Make sure packet is actually of even length. 13821479Ssklower */ 13921479Ssklower 14021479Ssklower if (len & 1) { 14121479Ssklower m = mprev; 14221479Ssklower if (m->m_len + m->m_off < MMAXOFF) { 14321479Ssklower m->m_len++; 14421479Ssklower } else { 14521479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 14621479Ssklower 14721699Ssklower if (m1 == 0) { 14821699Ssklower m_freem(m0); 14921699Ssklower return (ENOBUFS); 15021699Ssklower } 15121479Ssklower m1->m_len = 1; 15221479Ssklower m1->m_off = MMAXOFF - 1; 15321479Ssklower * mtod(m1, char *) = 0; 15421479Ssklower m->m_next = m1; 15521479Ssklower } 15621479Ssklower } 15721479Ssklower 15821479Ssklower /* 15921479Ssklower * Fill in mbuf with extended IDP header 16021479Ssklower * and addresses and length put into network format. 16121479Ssklower */ 16221479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 16321479Ssklower m = m0; 16421479Ssklower idp = mtod(m, struct idp *); 16521479Ssklower } else { 16621479Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 16721479Ssklower if (m == 0) { 16821479Ssklower m_freem(m0); 16921479Ssklower return (ENOBUFS); 17021479Ssklower } 17126055Ssklower m->m_off = MMAXOFF - sizeof (struct idp) - 2; 17226055Ssklower /* adjust to start on longword bdry 17326055Ssklower for NSIP on gould */ 17421479Ssklower m->m_len = sizeof (struct idp); 17521479Ssklower m->m_next = m0; 17621479Ssklower idp = mtod(m, struct idp *); 17721479Ssklower idp->idp_tc = 0; 17821479Ssklower idp->idp_pt = nsp->nsp_dpt; 17921479Ssklower idp->idp_sna = nsp->nsp_laddr; 18021479Ssklower idp->idp_dna = nsp->nsp_faddr; 18121479Ssklower len += sizeof (struct idp); 18221479Ssklower } 18321479Ssklower 18421479Ssklower idp->idp_len = htons((u_short)len); 18521479Ssklower 18621479Ssklower if (idpcksum) { 18721479Ssklower idp->idp_sum = 0; 18821479Ssklower len = ((len - 1) | 1) + 1; 18921479Ssklower idp->idp_sum = ns_cksum(m, len); 19021479Ssklower } else 19121479Ssklower idp->idp_sum = 0xffff; 19221479Ssklower 19321479Ssklower /* 19421479Ssklower * Output datagram. 19521479Ssklower */ 19621479Ssklower so = nsp->nsp_socket; 19721479Ssklower if (so->so_options & SO_DONTROUTE) 19821479Ssklower return (ns_output(m, (struct route *)0, 19921479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 20021479Ssklower /* 20121479Ssklower * Use cached route for previous datagram if 20225042Ssklower * possible. If the previous net was the same 20325042Ssklower * and the interface was a broadcast medium, or 20425042Ssklower * if the previous destination was identical, 20525042Ssklower * then we are ok. 20621479Ssklower * 20721479Ssklower * NB: We don't handle broadcasts because that 20821479Ssklower * would require 3 subroutine calls. 20921479Ssklower */ 21021479Ssklower ro = &nsp->nsp_route; 21125042Ssklower #ifdef ancient_history 21225042Ssklower /* 21325042Ssklower * I think that this will all be handled in ns_pcbconnect! 21425042Ssklower */ 21525042Ssklower if (ro->ro_rt) { 21625042Ssklower if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { 21725042Ssklower /* 21825042Ssklower * This assumes we have no GH type routes 21925042Ssklower */ 22025042Ssklower if (ro->ro_rt->rt_flags & RTF_HOST) { 22125042Ssklower if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) 22225042Ssklower goto re_route; 22325042Ssklower 22425042Ssklower } 22525042Ssklower if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 22625042Ssklower register struct ns_addr *dst = 22725042Ssklower &satons_addr(ro->ro_dst); 22825042Ssklower dst->x_host = idp->idp_dna.x_host; 22925042Ssklower } 23025042Ssklower /* 23125042Ssklower * Otherwise, we go through the same gateway 23225042Ssklower * and dst is already set up. 23325042Ssklower */ 23425042Ssklower } else { 23525042Ssklower re_route: 23625042Ssklower RTFREE(ro->ro_rt); 23725042Ssklower ro->ro_rt = (struct rtentry *)0; 23825042Ssklower } 23921479Ssklower } 24025042Ssklower nsp->nsp_lastdst = idp->idp_dna; 24125042Ssklower #endif ancient_history 24225042Ssklower if (noIdpRoute) ro = 0; 24321479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 24421479Ssklower } 24524225Ssklower /* ARGSUSED */ 24621479Ssklower idp_ctloutput(req, so, level, name, value) 24721479Ssklower int req, level; 24821479Ssklower struct socket *so; 24921479Ssklower int name; 25021479Ssklower struct mbuf **value; 25121479Ssklower { 25221479Ssklower register struct mbuf *m; 25321479Ssklower struct nspcb *nsp = sotonspcb(so); 25421479Ssklower int mask, error = 0; 25523977Ssklower extern long ns_pexseq; 25621479Ssklower 25723500Ssklower if (nsp == NULL) 25823500Ssklower return (EINVAL); 25921479Ssklower 26021479Ssklower switch (req) { 26123500Ssklower 26221479Ssklower case PRCO_GETOPT: 26323500Ssklower if (value==NULL) 26423500Ssklower return (EINVAL); 26521479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 26623500Ssklower if (m==NULL) 26723500Ssklower return (ENOBUFS); 26821479Ssklower switch (name) { 26923500Ssklower 27024049Ssklower case SO_ALL_PACKETS: 27124049Ssklower mask = NSP_ALL_PACKETS; 27224049Ssklower goto get_flags; 27324049Ssklower 27421479Ssklower case SO_HEADERS_ON_INPUT: 27521479Ssklower mask = NSP_RAWIN; 27621479Ssklower goto get_flags; 27723500Ssklower 27821479Ssklower case SO_HEADERS_ON_OUTPUT: 27921479Ssklower mask = NSP_RAWOUT; 28021479Ssklower get_flags: 28121479Ssklower m->m_len = sizeof(short); 28221479Ssklower m->m_off = MMAXOFF - sizeof(short); 28321479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 28421479Ssklower break; 28523500Ssklower 28621479Ssklower case SO_DEFAULT_HEADERS: 28721479Ssklower m->m_len = sizeof(struct idp); 28821479Ssklower m->m_off = MMAXOFF - sizeof(struct idp); 28921479Ssklower { 29021479Ssklower register struct idp *idp = mtod(m, struct idp *); 29121479Ssklower idp->idp_len = 0; 29221479Ssklower idp->idp_sum = 0; 29321479Ssklower idp->idp_tc = 0; 29421479Ssklower idp->idp_pt = nsp->nsp_dpt; 29521479Ssklower idp->idp_dna = nsp->nsp_faddr; 29621479Ssklower idp->idp_sna = nsp->nsp_laddr; 29721479Ssklower } 29823977Ssklower break; 29923977Ssklower 30023977Ssklower case SO_SEQNO: 30123977Ssklower m->m_len = sizeof(long); 30223977Ssklower m->m_off = MMAXOFF - sizeof(long); 30323977Ssklower *mtod(m, long *) = ns_pexseq++; 30425335Ssklower break; 30525335Ssklower 30625335Ssklower default: 30725335Ssklower error = EINVAL; 30821479Ssklower } 30921479Ssklower *value = m; 31021479Ssklower break; 31123500Ssklower 31221479Ssklower case PRCO_SETOPT: 31321479Ssklower switch (name) { 31424225Ssklower int *ok; 31521479Ssklower 31624049Ssklower case SO_ALL_PACKETS: 31724049Ssklower mask = NSP_ALL_PACKETS; 31824049Ssklower goto set_head; 31924049Ssklower 32021479Ssklower case SO_HEADERS_ON_INPUT: 32121479Ssklower mask = NSP_RAWIN; 32221479Ssklower goto set_head; 32323500Ssklower 32421479Ssklower case SO_HEADERS_ON_OUTPUT: 32521479Ssklower mask = NSP_RAWOUT; 32621479Ssklower set_head: 32721479Ssklower if (value && *value) { 32821479Ssklower ok = mtod(*value, int *); 32921479Ssklower if (*ok) 33021479Ssklower nsp->nsp_flags |= mask; 33121479Ssklower else 33221479Ssklower nsp->nsp_flags &= ~mask; 33321479Ssklower } else error = EINVAL; 33421479Ssklower break; 33523500Ssklower 33621479Ssklower case SO_DEFAULT_HEADERS: 33721479Ssklower { 33821479Ssklower register struct idp *idp 33921479Ssklower = mtod(*value, struct idp *); 34021479Ssklower nsp->nsp_dpt = idp->idp_pt; 34121479Ssklower } 34225335Ssklower break; 34321479Ssklower #ifdef NSIP 34423500Ssklower 34521479Ssklower case SO_NSIP_ROUTE: 34621479Ssklower error = nsip_route(*value); 34725335Ssklower break; 34821479Ssklower #endif NSIP 34925335Ssklower default: 35025335Ssklower error = EINVAL; 35121479Ssklower } 35221479Ssklower if (value && *value) 35321479Ssklower m_freem(*value); 35421479Ssklower break; 35521479Ssklower } 35623500Ssklower return (error); 35721479Ssklower } 35821479Ssklower 35921479Ssklower /*ARGSUSED*/ 36021479Ssklower idp_usrreq(so, req, m, nam, rights) 36121479Ssklower struct socket *so; 36221479Ssklower int req; 36321479Ssklower struct mbuf *m, *nam, *rights; 36421479Ssklower { 36521479Ssklower struct nspcb *nsp = sotonspcb(so); 36621479Ssklower int error = 0; 36721479Ssklower 36821479Ssklower if (req == PRU_CONTROL) 36921479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 37021479Ssklower (struct ifnet *)rights)); 37121479Ssklower if (rights && rights->m_len) { 37221479Ssklower error = EINVAL; 37321479Ssklower goto release; 37421479Ssklower } 37521479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 37621479Ssklower error = EINVAL; 37721479Ssklower goto release; 37821479Ssklower } 37921479Ssklower switch (req) { 38021479Ssklower 38121479Ssklower case PRU_ATTACH: 38221479Ssklower if (nsp != NULL) { 38321479Ssklower error = EINVAL; 38421479Ssklower break; 38521479Ssklower } 38621479Ssklower error = ns_pcballoc(so, &nspcb); 38721479Ssklower if (error) 38821479Ssklower break; 38921479Ssklower error = soreserve(so, 2048, 2048); 39021479Ssklower if (error) 39121479Ssklower break; 39221479Ssklower break; 39321479Ssklower 39421479Ssklower case PRU_DETACH: 39521479Ssklower if (nsp == NULL) { 39621479Ssklower error = ENOTCONN; 39721479Ssklower break; 39821479Ssklower } 39921479Ssklower ns_pcbdetach(nsp); 40021479Ssklower break; 40121479Ssklower 40221479Ssklower case PRU_BIND: 40321479Ssklower error = ns_pcbbind(nsp, nam); 40421479Ssklower break; 40521479Ssklower 40621479Ssklower case PRU_LISTEN: 40721479Ssklower error = EOPNOTSUPP; 40821479Ssklower break; 40921479Ssklower 41021479Ssklower case PRU_CONNECT: 41121479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 41221479Ssklower error = EISCONN; 41321479Ssklower break; 41421479Ssklower } 41521479Ssklower error = ns_pcbconnect(nsp, nam); 41621479Ssklower if (error == 0) 41721479Ssklower soisconnected(so); 41821479Ssklower break; 41921479Ssklower 42021479Ssklower case PRU_CONNECT2: 42121479Ssklower error = EOPNOTSUPP; 42221479Ssklower break; 42321479Ssklower 42421479Ssklower case PRU_ACCEPT: 42521479Ssklower error = EOPNOTSUPP; 42621479Ssklower break; 42721479Ssklower 42821479Ssklower case PRU_DISCONNECT: 42921479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 43021479Ssklower error = ENOTCONN; 43121479Ssklower break; 43221479Ssklower } 43321479Ssklower ns_pcbdisconnect(nsp); 43421479Ssklower soisdisconnected(so); 43521479Ssklower break; 43621479Ssklower 43721479Ssklower case PRU_SHUTDOWN: 43821479Ssklower socantsendmore(so); 43921479Ssklower break; 44021479Ssklower 44121479Ssklower case PRU_SEND: 44221479Ssklower { 44321479Ssklower struct ns_addr laddr; 44421479Ssklower int s; 44521479Ssklower 44621479Ssklower if (nam) { 44721479Ssklower laddr = nsp->nsp_laddr; 44821479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 44921479Ssklower error = EISCONN; 45021479Ssklower break; 45121479Ssklower } 45221479Ssklower /* 45321479Ssklower * Must block input while temporarily connected. 45421479Ssklower */ 45521479Ssklower s = splnet(); 45621479Ssklower error = ns_pcbconnect(nsp, nam); 45721479Ssklower if (error) { 45821479Ssklower splx(s); 45921479Ssklower break; 46021479Ssklower } 46121479Ssklower } else { 46221479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 46321479Ssklower error = ENOTCONN; 46421479Ssklower break; 46521479Ssklower } 46621479Ssklower } 46721479Ssklower error = idp_output(nsp, m); 46821479Ssklower m = NULL; 46921479Ssklower if (nam) { 47021479Ssklower ns_pcbdisconnect(nsp); 47121479Ssklower splx(s); 47221479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 47321479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 47421479Ssklower } 47521479Ssklower } 47621479Ssklower break; 47721479Ssklower 47821479Ssklower case PRU_ABORT: 47921479Ssklower ns_pcbdetach(nsp); 48021479Ssklower sofree(so); 48121479Ssklower soisdisconnected(so); 48221479Ssklower break; 48321479Ssklower 48421479Ssklower case PRU_SOCKADDR: 48521479Ssklower ns_setsockaddr(nsp, nam); 48621479Ssklower break; 48721479Ssklower 48821479Ssklower case PRU_PEERADDR: 48921479Ssklower ns_setpeeraddr(nsp, nam); 49021479Ssklower break; 49121479Ssklower 49221479Ssklower case PRU_SENSE: 49321479Ssklower /* 49421479Ssklower * stat: don't bother with a blocksize. 49521479Ssklower */ 49621479Ssklower return (0); 49721479Ssklower 49821479Ssklower case PRU_SENDOOB: 49921479Ssklower case PRU_FASTTIMO: 50021479Ssklower case PRU_SLOWTIMO: 50121479Ssklower case PRU_PROTORCV: 50221479Ssklower case PRU_PROTOSEND: 50321479Ssklower error = EOPNOTSUPP; 50421479Ssklower break; 50521479Ssklower 50621479Ssklower case PRU_CONTROL: 50721479Ssklower case PRU_RCVD: 50821479Ssklower case PRU_RCVOOB: 50921479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 51021479Ssklower 51121479Ssklower default: 51221479Ssklower panic("idp_usrreq"); 51321479Ssklower } 51421479Ssklower release: 51521479Ssklower if (m != NULL) 51621479Ssklower m_freem(m); 51721479Ssklower return (error); 51821479Ssklower } 51921479Ssklower /*ARGSUSED*/ 52021479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 52121479Ssklower struct socket *so; 52221479Ssklower int req; 52321479Ssklower struct mbuf *m, *nam, *rights; 52421479Ssklower { 52521479Ssklower int error = 0; 52621479Ssklower struct nspcb *nsp = sotonspcb(so); 52721479Ssklower extern struct nspcb nsrawpcb; 52821479Ssklower 52921479Ssklower switch (req) { 53021479Ssklower 53121479Ssklower case PRU_ATTACH: 53221479Ssklower 53321699Ssklower if (!suser() || (nsp != NULL)) { 53421479Ssklower error = EINVAL; 53521479Ssklower break; 53621479Ssklower } 53721479Ssklower error = ns_pcballoc(so, &nsrawpcb); 53821479Ssklower if (error) 53921479Ssklower break; 54021479Ssklower error = soreserve(so, 2048, 2048); 54121479Ssklower if (error) 54221479Ssklower break; 54321479Ssklower nsp = sotonspcb(so); 54421479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 54521479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 54621479Ssklower break; 54721479Ssklower default: 54821479Ssklower error = idp_usrreq(so, req, m, nam, rights); 54921479Ssklower } 55023500Ssklower return (error); 55121479Ssklower } 55221479Ssklower 553