123202Smckusick /* 223202Smckusick * Copyright (c) 1982 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*23977Ssklower * @(#)idp_usrreq.c 6.5 (Berkeley) 07/19/85 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" 2421479Ssklower #include "idp.h" 2521479Ssklower #include "idp_var.h" 2621479Ssklower #include "ns_error.h" 2721479Ssklower 2821479Ssklower /* 2921479Ssklower * IDP protocol implementation. 3021479Ssklower */ 3121479Ssklower 3221479Ssklower struct sockaddr_ns idp_ns = { AF_NS }; 3321479Ssklower 34*23977Ssklower /* 35*23977Ssklower * This may also be called for raw listeners. 36*23977Ssklower */ 3721479Ssklower idp_input(m, nsp) 3821479Ssklower struct mbuf *m; 3921479Ssklower register struct nspcb *nsp; 4021479Ssklower { 4121479Ssklower register struct idp *idp = mtod(m, struct idp *); 4221479Ssklower 43*23977Ssklower if (nsp==0) { 44*23977Ssklower nsp = ns_pcblookup(&idp->idp_sna, 45*23977Ssklower idp->idp_dna.x_port, NS_WILDCARD); 46*23977Ssklower if (nsp==0) { 47*23977Ssklower ns_error(m, NS_ERR_NOSOCK, 0); 48*23977Ssklower return; 49*23977Ssklower } 50*23977Ssklower } 51*23977Ssklower 5221479Ssklower /* 5321479Ssklower * Construct sockaddr format source address. 5421479Ssklower * Stuff source address and datagram in user buffer. 5521479Ssklower */ 5621479Ssklower idp_ns.sns_addr = idp->idp_sna; 5721479Ssklower nsp->nsp_rpt = idp->idp_pt; 5821479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 5921479Ssklower m->m_len -= sizeof (struct idp); 6021479Ssklower m->m_off += sizeof (struct idp); 6121479Ssklower } 6221479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 6321479Ssklower m, (struct mbuf *)0) == 0) 6421479Ssklower goto bad; 6521479Ssklower sorwakeup(nsp->nsp_socket); 6621479Ssklower return; 6721479Ssklower bad: 6821479Ssklower m_freem(m); 6921479Ssklower } 7021479Ssklower 7121479Ssklower idp_abort(nsp) 7221479Ssklower struct nspcb *nsp; 7321479Ssklower { 7421479Ssklower struct socket *so = nsp->nsp_socket; 7521479Ssklower 7621479Ssklower ns_pcbdisconnect(nsp); 7721479Ssklower soisdisconnected(so); 7821479Ssklower } 79*23977Ssklower /* 80*23977Ssklower * Drop connection, reporting 81*23977Ssklower * the specified error. 82*23977Ssklower */ 83*23977Ssklower struct nspcb * 84*23977Ssklower idp_drop(nsp, errno) 85*23977Ssklower register struct nspcb *nsp; 86*23977Ssklower int errno; 87*23977Ssklower { 88*23977Ssklower struct socket *so = nsp->nsp_socket; 8921479Ssklower 90*23977Ssklower /* 91*23977Ssklower * someday, in the xerox world 92*23977Ssklower * we will generate error protocol packets 93*23977Ssklower * announcing that the socket has gone away. 94*23977Ssklower */ 95*23977Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 96*23977Ssklower tp->t_state = TCPS_CLOSED; 97*23977Ssklower (void) tcp_output(tp); 98*23977Ssklower }*/ 99*23977Ssklower so->so_error = errno; 100*23977Ssklower ns_pcbdisconnect(nsp); 101*23977Ssklower soisdisconnected(so); 102*23977Ssklower } 103*23977Ssklower 10421479Ssklower idp_output(nsp, m0) 10521479Ssklower struct nspcb *nsp; 10621479Ssklower struct mbuf *m0; 10721479Ssklower { 10821479Ssklower register struct mbuf *m; 10921479Ssklower register struct idp *idp; 11021479Ssklower register struct socket *so; 11121479Ssklower register int len = 0; 11221479Ssklower register struct route *ro; 11321479Ssklower struct mbuf *mprev; 11421479Ssklower extern int idpcksum; 11521479Ssklower 11621479Ssklower /* 11721479Ssklower * Calculate data length. 11821479Ssklower */ 11921479Ssklower for (m = m0; m; m = m->m_next) { 12021479Ssklower mprev = m; 12121479Ssklower len += m->m_len; 12221479Ssklower } 12321479Ssklower /* 12421479Ssklower * Make sure packet is actually of even length. 12521479Ssklower */ 12621479Ssklower 12721479Ssklower if (len & 1) { 12821479Ssklower m = mprev; 12921479Ssklower if (m->m_len + m->m_off < MMAXOFF) { 13021479Ssklower m->m_len++; 13121479Ssklower } else { 13221479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 13321479Ssklower 13421699Ssklower if (m1 == 0) { 13521699Ssklower m_freem(m0); 13621699Ssklower return (ENOBUFS); 13721699Ssklower } 13821479Ssklower m1->m_len = 1; 13921479Ssklower m1->m_off = MMAXOFF - 1; 14021479Ssklower * mtod(m1, char *) = 0; 14121479Ssklower m->m_next = m1; 14221479Ssklower } 14321479Ssklower } 14421479Ssklower 14521479Ssklower /* 14621479Ssklower * Fill in mbuf with extended IDP header 14721479Ssklower * and addresses and length put into network format. 14821479Ssklower */ 14921479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 15021479Ssklower m = m0; 15121479Ssklower idp = mtod(m, struct idp *); 15221479Ssklower } else { 15321479Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 15421479Ssklower if (m == 0) { 15521479Ssklower m_freem(m0); 15621479Ssklower return (ENOBUFS); 15721479Ssklower } 15821479Ssklower m->m_off = MMAXOFF - sizeof (struct idp); 15921479Ssklower m->m_len = sizeof (struct idp); 16021479Ssklower m->m_next = m0; 16121479Ssklower idp = mtod(m, struct idp *); 16221479Ssklower idp->idp_tc = 0; 16321479Ssklower idp->idp_pt = nsp->nsp_dpt; 16421479Ssklower idp->idp_sna = nsp->nsp_laddr; 16521479Ssklower idp->idp_dna = nsp->nsp_faddr; 16621479Ssklower len += sizeof (struct idp); 16721479Ssklower } 16821479Ssklower 16921479Ssklower idp->idp_len = htons((u_short)len); 17021479Ssklower 17121479Ssklower if (idpcksum) { 17221479Ssklower idp->idp_sum = 0; 17321479Ssklower len = ((len - 1) | 1) + 1; 17421479Ssklower idp->idp_sum = ns_cksum(m, len); 17521479Ssklower } else 17621479Ssklower idp->idp_sum = 0xffff; 17721479Ssklower 17821479Ssklower /* 17921479Ssklower * Output datagram. 18021479Ssklower */ 18121479Ssklower so = nsp->nsp_socket; 18221479Ssklower if (so->so_options & SO_DONTROUTE) 18321479Ssklower return (ns_output(m, (struct route *)0, 18421479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 18521479Ssklower /* 18621479Ssklower * Use cached route for previous datagram if 18721479Ssklower * this is also to the same destination. 18821479Ssklower * 18921479Ssklower * NB: We don't handle broadcasts because that 19021479Ssklower * would require 3 subroutine calls. 19121479Ssklower */ 19221479Ssklower ro = &nsp->nsp_route; 19321479Ssklower if (ro->ro_rt && 19421479Ssklower ((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) && 19521479Ssklower !(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) { 19621479Ssklower RTFREE(ro->ro_rt); 19721479Ssklower ro->ro_rt = (struct rtentry *)0; 19821479Ssklower nsp->nsp_lastnet = idp->idp_dna.x_net; 19921479Ssklower } 20021479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 20121479Ssklower } 20221479Ssklower /*ARGSUSED*/ 20321479Ssklower idp_ctloutput(req, so, level, name, value) 20421479Ssklower int req, level; 20521479Ssklower struct socket *so; 20621479Ssklower int name; 20721479Ssklower struct mbuf **value; 20821479Ssklower { 20921479Ssklower register struct mbuf *m; 21021479Ssklower struct nspcb *nsp = sotonspcb(so); 21121479Ssklower int mask, error = 0; 212*23977Ssklower extern long ns_pexseq; 21321479Ssklower 21423500Ssklower if (nsp == NULL) 21523500Ssklower return (EINVAL); 21621479Ssklower 21721479Ssklower switch (req) { 21823500Ssklower 21921479Ssklower case PRCO_GETOPT: 22023500Ssklower if (value==NULL) 22123500Ssklower return (EINVAL); 22221479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 22323500Ssklower if (m==NULL) 22423500Ssklower return (ENOBUFS); 22521479Ssklower switch (name) { 22623500Ssklower 22721479Ssklower case SO_HEADERS_ON_INPUT: 22821479Ssklower mask = NSP_RAWIN; 22921479Ssklower goto get_flags; 23023500Ssklower 23121479Ssklower case SO_HEADERS_ON_OUTPUT: 23221479Ssklower mask = NSP_RAWOUT; 23321479Ssklower get_flags: 23421479Ssklower m->m_len = sizeof(short); 23521479Ssklower m->m_off = MMAXOFF - sizeof(short); 23621479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 23721479Ssklower break; 23823500Ssklower 23921479Ssklower case SO_DEFAULT_HEADERS: 24021479Ssklower m->m_len = sizeof(struct idp); 24121479Ssklower m->m_off = MMAXOFF - sizeof(struct idp); 24221479Ssklower { 24321479Ssklower register struct idp *idp = mtod(m, struct idp *); 24421479Ssklower idp->idp_len = 0; 24521479Ssklower idp->idp_sum = 0; 24621479Ssklower idp->idp_tc = 0; 24721479Ssklower idp->idp_pt = nsp->nsp_dpt; 24821479Ssklower idp->idp_dna = nsp->nsp_faddr; 24921479Ssklower idp->idp_sna = nsp->nsp_laddr; 25021479Ssklower } 251*23977Ssklower break; 252*23977Ssklower 253*23977Ssklower case SO_SEQNO: 254*23977Ssklower m->m_len = sizeof(long); 255*23977Ssklower m->m_off = MMAXOFF - sizeof(long); 256*23977Ssklower *mtod(m, long *) = ns_pexseq++; 25721479Ssklower } 25821479Ssklower *value = m; 25921479Ssklower break; 26023500Ssklower 26121479Ssklower case PRCO_SETOPT: 26221479Ssklower switch (name) { 26321479Ssklower int mask, *ok; 26421479Ssklower 26521479Ssklower case SO_HEADERS_ON_INPUT: 26621479Ssklower mask = NSP_RAWIN; 26721479Ssklower goto set_head; 26823500Ssklower 26921479Ssklower case SO_HEADERS_ON_OUTPUT: 27021479Ssklower mask = NSP_RAWOUT; 27121479Ssklower set_head: 27221479Ssklower if (value && *value) { 27321479Ssklower ok = mtod(*value, int *); 27421479Ssklower if (*ok) 27521479Ssklower nsp->nsp_flags |= mask; 27621479Ssklower else 27721479Ssklower nsp->nsp_flags &= ~mask; 27821479Ssklower } else error = EINVAL; 27921479Ssklower break; 28023500Ssklower 28121479Ssklower case SO_DEFAULT_HEADERS: 28221479Ssklower { 28321479Ssklower register struct idp *idp 28421479Ssklower = mtod(*value, struct idp *); 28521479Ssklower nsp->nsp_dpt = idp->idp_pt; 28621479Ssklower } 28721479Ssklower #ifdef NSIP 28821479Ssklower break; 28923500Ssklower 29021479Ssklower case SO_NSIP_ROUTE: 29121479Ssklower error = nsip_route(*value); 29221479Ssklower #endif NSIP 29321479Ssklower } 29421479Ssklower if (value && *value) 29521479Ssklower m_freem(*value); 29621479Ssklower break; 29721479Ssklower } 29823500Ssklower return (error); 29921479Ssklower } 30021479Ssklower 30121479Ssklower /*ARGSUSED*/ 30221479Ssklower idp_usrreq(so, req, m, nam, rights) 30321479Ssklower struct socket *so; 30421479Ssklower int req; 30521479Ssklower struct mbuf *m, *nam, *rights; 30621479Ssklower { 30721479Ssklower struct nspcb *nsp = sotonspcb(so); 30821479Ssklower int error = 0; 30921479Ssklower 31021479Ssklower if (req == PRU_CONTROL) 31121479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 31221479Ssklower (struct ifnet *)rights)); 31321479Ssklower if (rights && rights->m_len) { 31421479Ssklower error = EINVAL; 31521479Ssklower goto release; 31621479Ssklower } 31721479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 31821479Ssklower error = EINVAL; 31921479Ssklower goto release; 32021479Ssklower } 32121479Ssklower switch (req) { 32221479Ssklower 32321479Ssklower case PRU_ATTACH: 32421479Ssklower if (nsp != NULL) { 32521479Ssklower error = EINVAL; 32621479Ssklower break; 32721479Ssklower } 32821479Ssklower error = ns_pcballoc(so, &nspcb); 32921479Ssklower if (error) 33021479Ssklower break; 33121479Ssklower error = soreserve(so, 2048, 2048); 33221479Ssklower if (error) 33321479Ssklower break; 33421479Ssklower break; 33521479Ssklower 33621479Ssklower case PRU_DETACH: 33721479Ssklower if (nsp == NULL) { 33821479Ssklower error = ENOTCONN; 33921479Ssklower break; 34021479Ssklower } 34121479Ssklower ns_pcbdetach(nsp); 34221479Ssklower break; 34321479Ssklower 34421479Ssklower case PRU_BIND: 34521479Ssklower error = ns_pcbbind(nsp, nam); 34621479Ssklower break; 34721479Ssklower 34821479Ssklower case PRU_LISTEN: 34921479Ssklower error = EOPNOTSUPP; 35021479Ssklower break; 35121479Ssklower 35221479Ssklower case PRU_CONNECT: 35321479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 35421479Ssklower error = EISCONN; 35521479Ssklower break; 35621479Ssklower } 35721479Ssklower error = ns_pcbconnect(nsp, nam); 35821479Ssklower if (error == 0) 35921479Ssklower soisconnected(so); 36021479Ssklower break; 36121479Ssklower 36221479Ssklower case PRU_CONNECT2: 36321479Ssklower error = EOPNOTSUPP; 36421479Ssklower break; 36521479Ssklower 36621479Ssklower case PRU_ACCEPT: 36721479Ssklower error = EOPNOTSUPP; 36821479Ssklower break; 36921479Ssklower 37021479Ssklower case PRU_DISCONNECT: 37121479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 37221479Ssklower error = ENOTCONN; 37321479Ssklower break; 37421479Ssklower } 37521479Ssklower ns_pcbdisconnect(nsp); 37621479Ssklower soisdisconnected(so); 37721479Ssklower break; 37821479Ssklower 37921479Ssklower case PRU_SHUTDOWN: 38021479Ssklower socantsendmore(so); 38121479Ssklower break; 38221479Ssklower 38321479Ssklower case PRU_SEND: 38421479Ssklower { 38521479Ssklower struct ns_addr laddr; 38621479Ssklower int s; 38721479Ssklower 38821479Ssklower if (nam) { 38921479Ssklower laddr = nsp->nsp_laddr; 39021479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 39121479Ssklower error = EISCONN; 39221479Ssklower break; 39321479Ssklower } 39421479Ssklower /* 39521479Ssklower * Must block input while temporarily connected. 39621479Ssklower */ 39721479Ssklower s = splnet(); 39821479Ssklower error = ns_pcbconnect(nsp, nam); 39921479Ssklower if (error) { 40021479Ssklower splx(s); 40121479Ssklower break; 40221479Ssklower } 40321479Ssklower } else { 40421479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 40521479Ssklower error = ENOTCONN; 40621479Ssklower break; 40721479Ssklower } 40821479Ssklower } 40921479Ssklower error = idp_output(nsp, m); 41021479Ssklower m = NULL; 41121479Ssklower if (nam) { 41221479Ssklower ns_pcbdisconnect(nsp); 41321479Ssklower splx(s); 41421479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 41521479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 41621479Ssklower } 41721479Ssklower } 41821479Ssklower break; 41921479Ssklower 42021479Ssklower case PRU_ABORT: 42121479Ssklower ns_pcbdetach(nsp); 42221479Ssklower sofree(so); 42321479Ssklower soisdisconnected(so); 42421479Ssklower break; 42521479Ssklower 42621479Ssklower case PRU_SOCKADDR: 42721479Ssklower ns_setsockaddr(nsp, nam); 42821479Ssklower break; 42921479Ssklower 43021479Ssklower case PRU_PEERADDR: 43121479Ssklower ns_setpeeraddr(nsp, nam); 43221479Ssklower break; 43321479Ssklower 43421479Ssklower case PRU_SENSE: 43521479Ssklower /* 43621479Ssklower * stat: don't bother with a blocksize. 43721479Ssklower */ 43821479Ssklower return (0); 43921479Ssklower 44021479Ssklower case PRU_SENDOOB: 44121479Ssklower case PRU_FASTTIMO: 44221479Ssklower case PRU_SLOWTIMO: 44321479Ssklower case PRU_PROTORCV: 44421479Ssklower case PRU_PROTOSEND: 44521479Ssklower error = EOPNOTSUPP; 44621479Ssklower break; 44721479Ssklower 44821479Ssklower case PRU_CONTROL: 44921479Ssklower case PRU_RCVD: 45021479Ssklower case PRU_RCVOOB: 45121479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 45221479Ssklower 45321479Ssklower default: 45421479Ssklower panic("idp_usrreq"); 45521479Ssklower } 45621479Ssklower release: 45721479Ssklower if (m != NULL) 45821479Ssklower m_freem(m); 45921479Ssklower return (error); 46021479Ssklower } 46121479Ssklower /*ARGSUSED*/ 46221479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 46321479Ssklower struct socket *so; 46421479Ssklower int req; 46521479Ssklower struct mbuf *m, *nam, *rights; 46621479Ssklower { 46721479Ssklower int error = 0; 46821479Ssklower struct nspcb *nsp = sotonspcb(so); 46921479Ssklower extern struct nspcb nsrawpcb; 47021479Ssklower 47121479Ssklower switch (req) { 47221479Ssklower 47321479Ssklower case PRU_ATTACH: 47421479Ssklower 47521699Ssklower if (!suser() || (nsp != NULL)) { 47621479Ssklower error = EINVAL; 47721479Ssklower break; 47821479Ssklower } 47921479Ssklower error = ns_pcballoc(so, &nsrawpcb); 48021479Ssklower if (error) 48121479Ssklower break; 48221479Ssklower error = soreserve(so, 2048, 2048); 48321479Ssklower if (error) 48421479Ssklower break; 48521479Ssklower nsp = sotonspcb(so); 48621479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 48721479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 48821479Ssklower break; 48921479Ssklower default: 49021479Ssklower error = idp_usrreq(so, req, m, nam, rights); 49121479Ssklower } 49223500Ssklower return (error); 49321479Ssklower } 49421479Ssklower 495