123202Smckusick /* 2*26055Ssklower * Copyright (c) 1984, 1985 Regents of the University of California. 323202Smckusick * All rights reserved. The Berkeley software License Agreement 423202Smckusick * specifies the terms and conditions for redistribution. 523202Smckusick * 6*26055Ssklower * @(#)idp_usrreq.c 6.12 (Berkeley) 02/03/86 723202Smckusick */ 821479Ssklower 921479Ssklower #include "param.h" 1021479Ssklower #include "dir.h" 1121479Ssklower #include "user.h" 1221479Ssklower #include "mbuf.h" 1321479Ssklower #include "protosw.h" 1421479Ssklower #include "socket.h" 1521479Ssklower #include "socketvar.h" 1621479Ssklower #include "errno.h" 1721479Ssklower #include "stat.h" 1821479Ssklower 1921479Ssklower #include "../net/if.h" 2021479Ssklower #include "../net/route.h" 2121479Ssklower 2221479Ssklower #include "ns.h" 2321479Ssklower #include "ns_pcb.h" 2424611Ssklower #include "ns_if.h" 2521479Ssklower #include "idp.h" 2621479Ssklower #include "idp_var.h" 2721479Ssklower #include "ns_error.h" 2821479Ssklower 2921479Ssklower /* 3021479Ssklower * IDP protocol implementation. 3121479Ssklower */ 3221479Ssklower 3321479Ssklower struct sockaddr_ns idp_ns = { AF_NS }; 3421479Ssklower 3523977Ssklower /* 3623977Ssklower * This may also be called for raw listeners. 3723977Ssklower */ 3824611Ssklower idp_input(m, nsp, ifp) 3921479Ssklower struct mbuf *m; 4021479Ssklower register struct nspcb *nsp; 4124611Ssklower struct ifnet *ifp; 4221479Ssklower { 4321479Ssklower register struct idp *idp = mtod(m, struct idp *); 4421479Ssklower 4524611Ssklower if (nsp==0) 4624049Ssklower panic("No nspcb"); 4721479Ssklower /* 4821479Ssklower * Construct sockaddr format source address. 4921479Ssklower * Stuff source address and datagram in user buffer. 5021479Ssklower */ 5121479Ssklower idp_ns.sns_addr = idp->idp_sna; 52*26055Ssklower if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { 5324611Ssklower register struct ifaddr *ia; 5424611Ssklower 5524685Ssklower for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { 5624611Ssklower if (ia->ifa_addr.sa_family == AF_NS) { 5724611Ssklower idp_ns.sns_addr.x_net = 5824611Ssklower IA_SNS(ia)->sns_addr.x_net; 5924611Ssklower break; 6024611Ssklower } 6124611Ssklower } 6224611Ssklower } 6321479Ssklower nsp->nsp_rpt = idp->idp_pt; 6421479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 6521479Ssklower m->m_len -= sizeof (struct idp); 6621479Ssklower m->m_off += sizeof (struct idp); 6721479Ssklower } 6821479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 6921479Ssklower m, (struct mbuf *)0) == 0) 7021479Ssklower goto bad; 7121479Ssklower sorwakeup(nsp->nsp_socket); 7221479Ssklower return; 7321479Ssklower bad: 7421479Ssklower m_freem(m); 7521479Ssklower } 7621479Ssklower 7721479Ssklower idp_abort(nsp) 7821479Ssklower struct nspcb *nsp; 7921479Ssklower { 8021479Ssklower struct socket *so = nsp->nsp_socket; 8121479Ssklower 8221479Ssklower ns_pcbdisconnect(nsp); 8321479Ssklower soisdisconnected(so); 8421479Ssklower } 8523977Ssklower /* 8623977Ssklower * Drop connection, reporting 8723977Ssklower * the specified error. 8823977Ssklower */ 8923977Ssklower struct nspcb * 9023977Ssklower idp_drop(nsp, errno) 9123977Ssklower register struct nspcb *nsp; 9223977Ssklower int errno; 9323977Ssklower { 9423977Ssklower struct socket *so = nsp->nsp_socket; 9521479Ssklower 9623977Ssklower /* 9723977Ssklower * someday, in the xerox world 9823977Ssklower * we will generate error protocol packets 9923977Ssklower * announcing that the socket has gone away. 10023977Ssklower */ 10123977Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 10223977Ssklower tp->t_state = TCPS_CLOSED; 10323977Ssklower (void) tcp_output(tp); 10423977Ssklower }*/ 10523977Ssklower so->so_error = errno; 10623977Ssklower ns_pcbdisconnect(nsp); 10723977Ssklower soisdisconnected(so); 10823977Ssklower } 10923977Ssklower 11025042Ssklower int noIdpRoute; 11121479Ssklower idp_output(nsp, m0) 11221479Ssklower struct nspcb *nsp; 11321479Ssklower struct mbuf *m0; 11421479Ssklower { 11521479Ssklower register struct mbuf *m; 11621479Ssklower register struct idp *idp; 11721479Ssklower register struct socket *so; 11821479Ssklower register int len = 0; 11921479Ssklower register struct route *ro; 12021479Ssklower struct mbuf *mprev; 12121479Ssklower extern int idpcksum; 12221479Ssklower 12321479Ssklower /* 12421479Ssklower * Calculate data length. 12521479Ssklower */ 12621479Ssklower for (m = m0; m; m = m->m_next) { 12721479Ssklower mprev = m; 12821479Ssklower len += m->m_len; 12921479Ssklower } 13021479Ssklower /* 13121479Ssklower * Make sure packet is actually of even length. 13221479Ssklower */ 13321479Ssklower 13421479Ssklower if (len & 1) { 13521479Ssklower m = mprev; 13621479Ssklower if (m->m_len + m->m_off < MMAXOFF) { 13721479Ssklower m->m_len++; 13821479Ssklower } else { 13921479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 14021479Ssklower 14121699Ssklower if (m1 == 0) { 14221699Ssklower m_freem(m0); 14321699Ssklower return (ENOBUFS); 14421699Ssklower } 14521479Ssklower m1->m_len = 1; 14621479Ssklower m1->m_off = MMAXOFF - 1; 14721479Ssklower * mtod(m1, char *) = 0; 14821479Ssklower m->m_next = m1; 14921479Ssklower } 15021479Ssklower } 15121479Ssklower 15221479Ssklower /* 15321479Ssklower * Fill in mbuf with extended IDP header 15421479Ssklower * and addresses and length put into network format. 15521479Ssklower */ 15621479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 15721479Ssklower m = m0; 15821479Ssklower idp = mtod(m, struct idp *); 15921479Ssklower } else { 16021479Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 16121479Ssklower if (m == 0) { 16221479Ssklower m_freem(m0); 16321479Ssklower return (ENOBUFS); 16421479Ssklower } 165*26055Ssklower m->m_off = MMAXOFF - sizeof (struct idp) - 2; 166*26055Ssklower /* adjust to start on longword bdry 167*26055Ssklower for NSIP on gould */ 16821479Ssklower m->m_len = sizeof (struct idp); 16921479Ssklower m->m_next = m0; 17021479Ssklower idp = mtod(m, struct idp *); 17121479Ssklower idp->idp_tc = 0; 17221479Ssklower idp->idp_pt = nsp->nsp_dpt; 17321479Ssklower idp->idp_sna = nsp->nsp_laddr; 17421479Ssklower idp->idp_dna = nsp->nsp_faddr; 17521479Ssklower len += sizeof (struct idp); 17621479Ssklower } 17721479Ssklower 17821479Ssklower idp->idp_len = htons((u_short)len); 17921479Ssklower 18021479Ssklower if (idpcksum) { 18121479Ssklower idp->idp_sum = 0; 18221479Ssklower len = ((len - 1) | 1) + 1; 18321479Ssklower idp->idp_sum = ns_cksum(m, len); 18421479Ssklower } else 18521479Ssklower idp->idp_sum = 0xffff; 18621479Ssklower 18721479Ssklower /* 18821479Ssklower * Output datagram. 18921479Ssklower */ 19021479Ssklower so = nsp->nsp_socket; 19121479Ssklower if (so->so_options & SO_DONTROUTE) 19221479Ssklower return (ns_output(m, (struct route *)0, 19321479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 19421479Ssklower /* 19521479Ssklower * Use cached route for previous datagram if 19625042Ssklower * possible. If the previous net was the same 19725042Ssklower * and the interface was a broadcast medium, or 19825042Ssklower * if the previous destination was identical, 19925042Ssklower * then we are ok. 20021479Ssklower * 20121479Ssklower * NB: We don't handle broadcasts because that 20221479Ssklower * would require 3 subroutine calls. 20321479Ssklower */ 20421479Ssklower ro = &nsp->nsp_route; 20525042Ssklower #ifdef ancient_history 20625042Ssklower /* 20725042Ssklower * I think that this will all be handled in ns_pcbconnect! 20825042Ssklower */ 20925042Ssklower if (ro->ro_rt) { 21025042Ssklower if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { 21125042Ssklower /* 21225042Ssklower * This assumes we have no GH type routes 21325042Ssklower */ 21425042Ssklower if (ro->ro_rt->rt_flags & RTF_HOST) { 21525042Ssklower if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) 21625042Ssklower goto re_route; 21725042Ssklower 21825042Ssklower } 21925042Ssklower if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 22025042Ssklower register struct ns_addr *dst = 22125042Ssklower &satons_addr(ro->ro_dst); 22225042Ssklower dst->x_host = idp->idp_dna.x_host; 22325042Ssklower } 22425042Ssklower /* 22525042Ssklower * Otherwise, we go through the same gateway 22625042Ssklower * and dst is already set up. 22725042Ssklower */ 22825042Ssklower } else { 22925042Ssklower re_route: 23025042Ssklower RTFREE(ro->ro_rt); 23125042Ssklower ro->ro_rt = (struct rtentry *)0; 23225042Ssklower } 23321479Ssklower } 23425042Ssklower nsp->nsp_lastdst = idp->idp_dna; 23525042Ssklower #endif ancient_history 23625042Ssklower if (noIdpRoute) ro = 0; 23721479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 23821479Ssklower } 23924225Ssklower /* ARGSUSED */ 24021479Ssklower idp_ctloutput(req, so, level, name, value) 24121479Ssklower int req, level; 24221479Ssklower struct socket *so; 24321479Ssklower int name; 24421479Ssklower struct mbuf **value; 24521479Ssklower { 24621479Ssklower register struct mbuf *m; 24721479Ssklower struct nspcb *nsp = sotonspcb(so); 24821479Ssklower int mask, error = 0; 24923977Ssklower extern long ns_pexseq; 25021479Ssklower 25123500Ssklower if (nsp == NULL) 25223500Ssklower return (EINVAL); 25321479Ssklower 25421479Ssklower switch (req) { 25523500Ssklower 25621479Ssklower case PRCO_GETOPT: 25723500Ssklower if (value==NULL) 25823500Ssklower return (EINVAL); 25921479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 26023500Ssklower if (m==NULL) 26123500Ssklower return (ENOBUFS); 26221479Ssklower switch (name) { 26323500Ssklower 26424049Ssklower case SO_ALL_PACKETS: 26524049Ssklower mask = NSP_ALL_PACKETS; 26624049Ssklower goto get_flags; 26724049Ssklower 26821479Ssklower case SO_HEADERS_ON_INPUT: 26921479Ssklower mask = NSP_RAWIN; 27021479Ssklower goto get_flags; 27123500Ssklower 27221479Ssklower case SO_HEADERS_ON_OUTPUT: 27321479Ssklower mask = NSP_RAWOUT; 27421479Ssklower get_flags: 27521479Ssklower m->m_len = sizeof(short); 27621479Ssklower m->m_off = MMAXOFF - sizeof(short); 27721479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 27821479Ssklower break; 27923500Ssklower 28021479Ssklower case SO_DEFAULT_HEADERS: 28121479Ssklower m->m_len = sizeof(struct idp); 28221479Ssklower m->m_off = MMAXOFF - sizeof(struct idp); 28321479Ssklower { 28421479Ssklower register struct idp *idp = mtod(m, struct idp *); 28521479Ssklower idp->idp_len = 0; 28621479Ssklower idp->idp_sum = 0; 28721479Ssklower idp->idp_tc = 0; 28821479Ssklower idp->idp_pt = nsp->nsp_dpt; 28921479Ssklower idp->idp_dna = nsp->nsp_faddr; 29021479Ssklower idp->idp_sna = nsp->nsp_laddr; 29121479Ssklower } 29223977Ssklower break; 29323977Ssklower 29423977Ssklower case SO_SEQNO: 29523977Ssklower m->m_len = sizeof(long); 29623977Ssklower m->m_off = MMAXOFF - sizeof(long); 29723977Ssklower *mtod(m, long *) = ns_pexseq++; 29825335Ssklower break; 29925335Ssklower 30025335Ssklower default: 30125335Ssklower error = EINVAL; 30221479Ssklower } 30321479Ssklower *value = m; 30421479Ssklower break; 30523500Ssklower 30621479Ssklower case PRCO_SETOPT: 30721479Ssklower switch (name) { 30824225Ssklower int *ok; 30921479Ssklower 31024049Ssklower case SO_ALL_PACKETS: 31124049Ssklower mask = NSP_ALL_PACKETS; 31224049Ssklower goto set_head; 31324049Ssklower 31421479Ssklower case SO_HEADERS_ON_INPUT: 31521479Ssklower mask = NSP_RAWIN; 31621479Ssklower goto set_head; 31723500Ssklower 31821479Ssklower case SO_HEADERS_ON_OUTPUT: 31921479Ssklower mask = NSP_RAWOUT; 32021479Ssklower set_head: 32121479Ssklower if (value && *value) { 32221479Ssklower ok = mtod(*value, int *); 32321479Ssklower if (*ok) 32421479Ssklower nsp->nsp_flags |= mask; 32521479Ssklower else 32621479Ssklower nsp->nsp_flags &= ~mask; 32721479Ssklower } else error = EINVAL; 32821479Ssklower break; 32923500Ssklower 33021479Ssklower case SO_DEFAULT_HEADERS: 33121479Ssklower { 33221479Ssklower register struct idp *idp 33321479Ssklower = mtod(*value, struct idp *); 33421479Ssklower nsp->nsp_dpt = idp->idp_pt; 33521479Ssklower } 33625335Ssklower break; 33721479Ssklower #ifdef NSIP 33823500Ssklower 33921479Ssklower case SO_NSIP_ROUTE: 34021479Ssklower error = nsip_route(*value); 34125335Ssklower break; 34221479Ssklower #endif NSIP 34325335Ssklower default: 34425335Ssklower error = EINVAL; 34521479Ssklower } 34621479Ssklower if (value && *value) 34721479Ssklower m_freem(*value); 34821479Ssklower break; 34921479Ssklower } 35023500Ssklower return (error); 35121479Ssklower } 35221479Ssklower 35321479Ssklower /*ARGSUSED*/ 35421479Ssklower idp_usrreq(so, req, m, nam, rights) 35521479Ssklower struct socket *so; 35621479Ssklower int req; 35721479Ssklower struct mbuf *m, *nam, *rights; 35821479Ssklower { 35921479Ssklower struct nspcb *nsp = sotonspcb(so); 36021479Ssklower int error = 0; 36121479Ssklower 36221479Ssklower if (req == PRU_CONTROL) 36321479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 36421479Ssklower (struct ifnet *)rights)); 36521479Ssklower if (rights && rights->m_len) { 36621479Ssklower error = EINVAL; 36721479Ssklower goto release; 36821479Ssklower } 36921479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 37021479Ssklower error = EINVAL; 37121479Ssklower goto release; 37221479Ssklower } 37321479Ssklower switch (req) { 37421479Ssklower 37521479Ssklower case PRU_ATTACH: 37621479Ssklower if (nsp != NULL) { 37721479Ssklower error = EINVAL; 37821479Ssklower break; 37921479Ssklower } 38021479Ssklower error = ns_pcballoc(so, &nspcb); 38121479Ssklower if (error) 38221479Ssklower break; 38321479Ssklower error = soreserve(so, 2048, 2048); 38421479Ssklower if (error) 38521479Ssklower break; 38621479Ssklower break; 38721479Ssklower 38821479Ssklower case PRU_DETACH: 38921479Ssklower if (nsp == NULL) { 39021479Ssklower error = ENOTCONN; 39121479Ssklower break; 39221479Ssklower } 39321479Ssklower ns_pcbdetach(nsp); 39421479Ssklower break; 39521479Ssklower 39621479Ssklower case PRU_BIND: 39721479Ssklower error = ns_pcbbind(nsp, nam); 39821479Ssklower break; 39921479Ssklower 40021479Ssklower case PRU_LISTEN: 40121479Ssklower error = EOPNOTSUPP; 40221479Ssklower break; 40321479Ssklower 40421479Ssklower case PRU_CONNECT: 40521479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 40621479Ssklower error = EISCONN; 40721479Ssklower break; 40821479Ssklower } 40921479Ssklower error = ns_pcbconnect(nsp, nam); 41021479Ssklower if (error == 0) 41121479Ssklower soisconnected(so); 41221479Ssklower break; 41321479Ssklower 41421479Ssklower case PRU_CONNECT2: 41521479Ssklower error = EOPNOTSUPP; 41621479Ssklower break; 41721479Ssklower 41821479Ssklower case PRU_ACCEPT: 41921479Ssklower error = EOPNOTSUPP; 42021479Ssklower break; 42121479Ssklower 42221479Ssklower case PRU_DISCONNECT: 42321479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 42421479Ssklower error = ENOTCONN; 42521479Ssklower break; 42621479Ssklower } 42721479Ssklower ns_pcbdisconnect(nsp); 42821479Ssklower soisdisconnected(so); 42921479Ssklower break; 43021479Ssklower 43121479Ssklower case PRU_SHUTDOWN: 43221479Ssklower socantsendmore(so); 43321479Ssklower break; 43421479Ssklower 43521479Ssklower case PRU_SEND: 43621479Ssklower { 43721479Ssklower struct ns_addr laddr; 43821479Ssklower int s; 43921479Ssklower 44021479Ssklower if (nam) { 44121479Ssklower laddr = nsp->nsp_laddr; 44221479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 44321479Ssklower error = EISCONN; 44421479Ssklower break; 44521479Ssklower } 44621479Ssklower /* 44721479Ssklower * Must block input while temporarily connected. 44821479Ssklower */ 44921479Ssklower s = splnet(); 45021479Ssklower error = ns_pcbconnect(nsp, nam); 45121479Ssklower if (error) { 45221479Ssklower splx(s); 45321479Ssklower break; 45421479Ssklower } 45521479Ssklower } else { 45621479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 45721479Ssklower error = ENOTCONN; 45821479Ssklower break; 45921479Ssklower } 46021479Ssklower } 46121479Ssklower error = idp_output(nsp, m); 46221479Ssklower m = NULL; 46321479Ssklower if (nam) { 46421479Ssklower ns_pcbdisconnect(nsp); 46521479Ssklower splx(s); 46621479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 46721479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 46821479Ssklower } 46921479Ssklower } 47021479Ssklower break; 47121479Ssklower 47221479Ssklower case PRU_ABORT: 47321479Ssklower ns_pcbdetach(nsp); 47421479Ssklower sofree(so); 47521479Ssklower soisdisconnected(so); 47621479Ssklower break; 47721479Ssklower 47821479Ssklower case PRU_SOCKADDR: 47921479Ssklower ns_setsockaddr(nsp, nam); 48021479Ssklower break; 48121479Ssklower 48221479Ssklower case PRU_PEERADDR: 48321479Ssklower ns_setpeeraddr(nsp, nam); 48421479Ssklower break; 48521479Ssklower 48621479Ssklower case PRU_SENSE: 48721479Ssklower /* 48821479Ssklower * stat: don't bother with a blocksize. 48921479Ssklower */ 49021479Ssklower return (0); 49121479Ssklower 49221479Ssklower case PRU_SENDOOB: 49321479Ssklower case PRU_FASTTIMO: 49421479Ssklower case PRU_SLOWTIMO: 49521479Ssklower case PRU_PROTORCV: 49621479Ssklower case PRU_PROTOSEND: 49721479Ssklower error = EOPNOTSUPP; 49821479Ssklower break; 49921479Ssklower 50021479Ssklower case PRU_CONTROL: 50121479Ssklower case PRU_RCVD: 50221479Ssklower case PRU_RCVOOB: 50321479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 50421479Ssklower 50521479Ssklower default: 50621479Ssklower panic("idp_usrreq"); 50721479Ssklower } 50821479Ssklower release: 50921479Ssklower if (m != NULL) 51021479Ssklower m_freem(m); 51121479Ssklower return (error); 51221479Ssklower } 51321479Ssklower /*ARGSUSED*/ 51421479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 51521479Ssklower struct socket *so; 51621479Ssklower int req; 51721479Ssklower struct mbuf *m, *nam, *rights; 51821479Ssklower { 51921479Ssklower int error = 0; 52021479Ssklower struct nspcb *nsp = sotonspcb(so); 52121479Ssklower extern struct nspcb nsrawpcb; 52221479Ssklower 52321479Ssklower switch (req) { 52421479Ssklower 52521479Ssklower case PRU_ATTACH: 52621479Ssklower 52721699Ssklower if (!suser() || (nsp != NULL)) { 52821479Ssklower error = EINVAL; 52921479Ssklower break; 53021479Ssklower } 53121479Ssklower error = ns_pcballoc(so, &nsrawpcb); 53221479Ssklower if (error) 53321479Ssklower break; 53421479Ssklower error = soreserve(so, 2048, 2048); 53521479Ssklower if (error) 53621479Ssklower break; 53721479Ssklower nsp = sotonspcb(so); 53821479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 53921479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 54021479Ssklower break; 54121479Ssklower default: 54221479Ssklower error = idp_usrreq(so, req, m, nam, rights); 54321479Ssklower } 54423500Ssklower return (error); 54521479Ssklower } 54621479Ssklower 547