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*24225Ssklower * @(#)idp_usrreq.c 6.7 (Berkeley) 08/09/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 3423977Ssklower /* 3523977Ssklower * This may also be called for raw listeners. 3623977Ssklower */ 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 4323977Ssklower if (nsp==0) { 4424049Ssklower panic("No nspcb"); 4523977Ssklower } 4623977Ssklower 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; 5221479Ssklower nsp->nsp_rpt = idp->idp_pt; 5321479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 5421479Ssklower m->m_len -= sizeof (struct idp); 5521479Ssklower m->m_off += sizeof (struct idp); 5621479Ssklower } 5721479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 5821479Ssklower m, (struct mbuf *)0) == 0) 5921479Ssklower goto bad; 6021479Ssklower sorwakeup(nsp->nsp_socket); 6121479Ssklower return; 6221479Ssklower bad: 6321479Ssklower m_freem(m); 6421479Ssklower } 6521479Ssklower 6621479Ssklower idp_abort(nsp) 6721479Ssklower struct nspcb *nsp; 6821479Ssklower { 6921479Ssklower struct socket *so = nsp->nsp_socket; 7021479Ssklower 7121479Ssklower ns_pcbdisconnect(nsp); 7221479Ssklower soisdisconnected(so); 7321479Ssklower } 7423977Ssklower /* 7523977Ssklower * Drop connection, reporting 7623977Ssklower * the specified error. 7723977Ssklower */ 7823977Ssklower struct nspcb * 7923977Ssklower idp_drop(nsp, errno) 8023977Ssklower register struct nspcb *nsp; 8123977Ssklower int errno; 8223977Ssklower { 8323977Ssklower struct socket *so = nsp->nsp_socket; 8421479Ssklower 8523977Ssklower /* 8623977Ssklower * someday, in the xerox world 8723977Ssklower * we will generate error protocol packets 8823977Ssklower * announcing that the socket has gone away. 8923977Ssklower */ 9023977Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 9123977Ssklower tp->t_state = TCPS_CLOSED; 9223977Ssklower (void) tcp_output(tp); 9323977Ssklower }*/ 9423977Ssklower so->so_error = errno; 9523977Ssklower ns_pcbdisconnect(nsp); 9623977Ssklower soisdisconnected(so); 9723977Ssklower } 9823977Ssklower 9921479Ssklower idp_output(nsp, m0) 10021479Ssklower struct nspcb *nsp; 10121479Ssklower struct mbuf *m0; 10221479Ssklower { 10321479Ssklower register struct mbuf *m; 10421479Ssklower register struct idp *idp; 10521479Ssklower register struct socket *so; 10621479Ssklower register int len = 0; 10721479Ssklower register struct route *ro; 10821479Ssklower struct mbuf *mprev; 10921479Ssklower extern int idpcksum; 11021479Ssklower 11121479Ssklower /* 11221479Ssklower * Calculate data length. 11321479Ssklower */ 11421479Ssklower for (m = m0; m; m = m->m_next) { 11521479Ssklower mprev = m; 11621479Ssklower len += m->m_len; 11721479Ssklower } 11821479Ssklower /* 11921479Ssklower * Make sure packet is actually of even length. 12021479Ssklower */ 12121479Ssklower 12221479Ssklower if (len & 1) { 12321479Ssklower m = mprev; 12421479Ssklower if (m->m_len + m->m_off < MMAXOFF) { 12521479Ssklower m->m_len++; 12621479Ssklower } else { 12721479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 12821479Ssklower 12921699Ssklower if (m1 == 0) { 13021699Ssklower m_freem(m0); 13121699Ssklower return (ENOBUFS); 13221699Ssklower } 13321479Ssklower m1->m_len = 1; 13421479Ssklower m1->m_off = MMAXOFF - 1; 13521479Ssklower * mtod(m1, char *) = 0; 13621479Ssklower m->m_next = m1; 13721479Ssklower } 13821479Ssklower } 13921479Ssklower 14021479Ssklower /* 14121479Ssklower * Fill in mbuf with extended IDP header 14221479Ssklower * and addresses and length put into network format. 14321479Ssklower */ 14421479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 14521479Ssklower m = m0; 14621479Ssklower idp = mtod(m, struct idp *); 14721479Ssklower } else { 14821479Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 14921479Ssklower if (m == 0) { 15021479Ssklower m_freem(m0); 15121479Ssklower return (ENOBUFS); 15221479Ssklower } 15321479Ssklower m->m_off = MMAXOFF - sizeof (struct idp); 15421479Ssklower m->m_len = sizeof (struct idp); 15521479Ssklower m->m_next = m0; 15621479Ssklower idp = mtod(m, struct idp *); 15721479Ssklower idp->idp_tc = 0; 15821479Ssklower idp->idp_pt = nsp->nsp_dpt; 15921479Ssklower idp->idp_sna = nsp->nsp_laddr; 16021479Ssklower idp->idp_dna = nsp->nsp_faddr; 16121479Ssklower len += sizeof (struct idp); 16221479Ssklower } 16321479Ssklower 16421479Ssklower idp->idp_len = htons((u_short)len); 16521479Ssklower 16621479Ssklower if (idpcksum) { 16721479Ssklower idp->idp_sum = 0; 16821479Ssklower len = ((len - 1) | 1) + 1; 16921479Ssklower idp->idp_sum = ns_cksum(m, len); 17021479Ssklower } else 17121479Ssklower idp->idp_sum = 0xffff; 17221479Ssklower 17321479Ssklower /* 17421479Ssklower * Output datagram. 17521479Ssklower */ 17621479Ssklower so = nsp->nsp_socket; 17721479Ssklower if (so->so_options & SO_DONTROUTE) 17821479Ssklower return (ns_output(m, (struct route *)0, 17921479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 18021479Ssklower /* 18121479Ssklower * Use cached route for previous datagram if 18221479Ssklower * this is also to the same destination. 18321479Ssklower * 18421479Ssklower * NB: We don't handle broadcasts because that 18521479Ssklower * would require 3 subroutine calls. 18621479Ssklower */ 18721479Ssklower ro = &nsp->nsp_route; 18821479Ssklower if (ro->ro_rt && 18921479Ssklower ((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) && 19021479Ssklower !(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) { 19121479Ssklower RTFREE(ro->ro_rt); 19221479Ssklower ro->ro_rt = (struct rtentry *)0; 19321479Ssklower nsp->nsp_lastnet = idp->idp_dna.x_net; 19421479Ssklower } 19521479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 19621479Ssklower } 197*24225Ssklower /* ARGSUSED */ 19821479Ssklower idp_ctloutput(req, so, level, name, value) 19921479Ssklower int req, level; 20021479Ssklower struct socket *so; 20121479Ssklower int name; 20221479Ssklower struct mbuf **value; 20321479Ssklower { 20421479Ssklower register struct mbuf *m; 20521479Ssklower struct nspcb *nsp = sotonspcb(so); 20621479Ssklower int mask, error = 0; 20723977Ssklower extern long ns_pexseq; 20821479Ssklower 20923500Ssklower if (nsp == NULL) 21023500Ssklower return (EINVAL); 21121479Ssklower 21221479Ssklower switch (req) { 21323500Ssklower 21421479Ssklower case PRCO_GETOPT: 21523500Ssklower if (value==NULL) 21623500Ssklower return (EINVAL); 21721479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 21823500Ssklower if (m==NULL) 21923500Ssklower return (ENOBUFS); 22021479Ssklower switch (name) { 22123500Ssklower 22224049Ssklower case SO_ALL_PACKETS: 22324049Ssklower mask = NSP_ALL_PACKETS; 22424049Ssklower goto get_flags; 22524049Ssklower 22621479Ssklower case SO_HEADERS_ON_INPUT: 22721479Ssklower mask = NSP_RAWIN; 22821479Ssklower goto get_flags; 22923500Ssklower 23021479Ssklower case SO_HEADERS_ON_OUTPUT: 23121479Ssklower mask = NSP_RAWOUT; 23221479Ssklower get_flags: 23321479Ssklower m->m_len = sizeof(short); 23421479Ssklower m->m_off = MMAXOFF - sizeof(short); 23521479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 23621479Ssklower break; 23723500Ssklower 23821479Ssklower case SO_DEFAULT_HEADERS: 23921479Ssklower m->m_len = sizeof(struct idp); 24021479Ssklower m->m_off = MMAXOFF - sizeof(struct idp); 24121479Ssklower { 24221479Ssklower register struct idp *idp = mtod(m, struct idp *); 24321479Ssklower idp->idp_len = 0; 24421479Ssklower idp->idp_sum = 0; 24521479Ssklower idp->idp_tc = 0; 24621479Ssklower idp->idp_pt = nsp->nsp_dpt; 24721479Ssklower idp->idp_dna = nsp->nsp_faddr; 24821479Ssklower idp->idp_sna = nsp->nsp_laddr; 24921479Ssklower } 25023977Ssklower break; 25123977Ssklower 25223977Ssklower case SO_SEQNO: 25323977Ssklower m->m_len = sizeof(long); 25423977Ssklower m->m_off = MMAXOFF - sizeof(long); 25523977Ssklower *mtod(m, long *) = ns_pexseq++; 25621479Ssklower } 25721479Ssklower *value = m; 25821479Ssklower break; 25923500Ssklower 26021479Ssklower case PRCO_SETOPT: 26121479Ssklower switch (name) { 262*24225Ssklower int *ok; 26321479Ssklower 26424049Ssklower case SO_ALL_PACKETS: 26524049Ssklower mask = NSP_ALL_PACKETS; 26624049Ssklower goto set_head; 26724049Ssklower 26821479Ssklower case SO_HEADERS_ON_INPUT: 26921479Ssklower mask = NSP_RAWIN; 27021479Ssklower goto set_head; 27123500Ssklower 27221479Ssklower case SO_HEADERS_ON_OUTPUT: 27321479Ssklower mask = NSP_RAWOUT; 27421479Ssklower set_head: 27521479Ssklower if (value && *value) { 27621479Ssklower ok = mtod(*value, int *); 27721479Ssklower if (*ok) 27821479Ssklower nsp->nsp_flags |= mask; 27921479Ssklower else 28021479Ssklower nsp->nsp_flags &= ~mask; 28121479Ssklower } else error = EINVAL; 28221479Ssklower break; 28323500Ssklower 28421479Ssklower case SO_DEFAULT_HEADERS: 28521479Ssklower { 28621479Ssklower register struct idp *idp 28721479Ssklower = mtod(*value, struct idp *); 28821479Ssklower nsp->nsp_dpt = idp->idp_pt; 28921479Ssklower } 29021479Ssklower #ifdef NSIP 29121479Ssklower break; 29223500Ssklower 29321479Ssklower case SO_NSIP_ROUTE: 29421479Ssklower error = nsip_route(*value); 29521479Ssklower #endif NSIP 29621479Ssklower } 29721479Ssklower if (value && *value) 29821479Ssklower m_freem(*value); 29921479Ssklower break; 30021479Ssklower } 30123500Ssklower return (error); 30221479Ssklower } 30321479Ssklower 30421479Ssklower /*ARGSUSED*/ 30521479Ssklower idp_usrreq(so, req, m, nam, rights) 30621479Ssklower struct socket *so; 30721479Ssklower int req; 30821479Ssklower struct mbuf *m, *nam, *rights; 30921479Ssklower { 31021479Ssklower struct nspcb *nsp = sotonspcb(so); 31121479Ssklower int error = 0; 31221479Ssklower 31321479Ssklower if (req == PRU_CONTROL) 31421479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 31521479Ssklower (struct ifnet *)rights)); 31621479Ssklower if (rights && rights->m_len) { 31721479Ssklower error = EINVAL; 31821479Ssklower goto release; 31921479Ssklower } 32021479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 32121479Ssklower error = EINVAL; 32221479Ssklower goto release; 32321479Ssklower } 32421479Ssklower switch (req) { 32521479Ssklower 32621479Ssklower case PRU_ATTACH: 32721479Ssklower if (nsp != NULL) { 32821479Ssklower error = EINVAL; 32921479Ssklower break; 33021479Ssklower } 33121479Ssklower error = ns_pcballoc(so, &nspcb); 33221479Ssklower if (error) 33321479Ssklower break; 33421479Ssklower error = soreserve(so, 2048, 2048); 33521479Ssklower if (error) 33621479Ssklower break; 33721479Ssklower break; 33821479Ssklower 33921479Ssklower case PRU_DETACH: 34021479Ssklower if (nsp == NULL) { 34121479Ssklower error = ENOTCONN; 34221479Ssklower break; 34321479Ssklower } 34421479Ssklower ns_pcbdetach(nsp); 34521479Ssklower break; 34621479Ssklower 34721479Ssklower case PRU_BIND: 34821479Ssklower error = ns_pcbbind(nsp, nam); 34921479Ssklower break; 35021479Ssklower 35121479Ssklower case PRU_LISTEN: 35221479Ssklower error = EOPNOTSUPP; 35321479Ssklower break; 35421479Ssklower 35521479Ssklower case PRU_CONNECT: 35621479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 35721479Ssklower error = EISCONN; 35821479Ssklower break; 35921479Ssklower } 36021479Ssklower error = ns_pcbconnect(nsp, nam); 36121479Ssklower if (error == 0) 36221479Ssklower soisconnected(so); 36321479Ssklower break; 36421479Ssklower 36521479Ssklower case PRU_CONNECT2: 36621479Ssklower error = EOPNOTSUPP; 36721479Ssklower break; 36821479Ssklower 36921479Ssklower case PRU_ACCEPT: 37021479Ssklower error = EOPNOTSUPP; 37121479Ssklower break; 37221479Ssklower 37321479Ssklower case PRU_DISCONNECT: 37421479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 37521479Ssklower error = ENOTCONN; 37621479Ssklower break; 37721479Ssklower } 37821479Ssklower ns_pcbdisconnect(nsp); 37921479Ssklower soisdisconnected(so); 38021479Ssklower break; 38121479Ssklower 38221479Ssklower case PRU_SHUTDOWN: 38321479Ssklower socantsendmore(so); 38421479Ssklower break; 38521479Ssklower 38621479Ssklower case PRU_SEND: 38721479Ssklower { 38821479Ssklower struct ns_addr laddr; 38921479Ssklower int s; 39021479Ssklower 39121479Ssklower if (nam) { 39221479Ssklower laddr = nsp->nsp_laddr; 39321479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 39421479Ssklower error = EISCONN; 39521479Ssklower break; 39621479Ssklower } 39721479Ssklower /* 39821479Ssklower * Must block input while temporarily connected. 39921479Ssklower */ 40021479Ssklower s = splnet(); 40121479Ssklower error = ns_pcbconnect(nsp, nam); 40221479Ssklower if (error) { 40321479Ssklower splx(s); 40421479Ssklower break; 40521479Ssklower } 40621479Ssklower } else { 40721479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 40821479Ssklower error = ENOTCONN; 40921479Ssklower break; 41021479Ssklower } 41121479Ssklower } 41221479Ssklower error = idp_output(nsp, m); 41321479Ssklower m = NULL; 41421479Ssklower if (nam) { 41521479Ssklower ns_pcbdisconnect(nsp); 41621479Ssklower splx(s); 41721479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 41821479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 41921479Ssklower } 42021479Ssklower } 42121479Ssklower break; 42221479Ssklower 42321479Ssklower case PRU_ABORT: 42421479Ssklower ns_pcbdetach(nsp); 42521479Ssklower sofree(so); 42621479Ssklower soisdisconnected(so); 42721479Ssklower break; 42821479Ssklower 42921479Ssklower case PRU_SOCKADDR: 43021479Ssklower ns_setsockaddr(nsp, nam); 43121479Ssklower break; 43221479Ssklower 43321479Ssklower case PRU_PEERADDR: 43421479Ssklower ns_setpeeraddr(nsp, nam); 43521479Ssklower break; 43621479Ssklower 43721479Ssklower case PRU_SENSE: 43821479Ssklower /* 43921479Ssklower * stat: don't bother with a blocksize. 44021479Ssklower */ 44121479Ssklower return (0); 44221479Ssklower 44321479Ssklower case PRU_SENDOOB: 44421479Ssklower case PRU_FASTTIMO: 44521479Ssklower case PRU_SLOWTIMO: 44621479Ssklower case PRU_PROTORCV: 44721479Ssklower case PRU_PROTOSEND: 44821479Ssklower error = EOPNOTSUPP; 44921479Ssklower break; 45021479Ssklower 45121479Ssklower case PRU_CONTROL: 45221479Ssklower case PRU_RCVD: 45321479Ssklower case PRU_RCVOOB: 45421479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 45521479Ssklower 45621479Ssklower default: 45721479Ssklower panic("idp_usrreq"); 45821479Ssklower } 45921479Ssklower release: 46021479Ssklower if (m != NULL) 46121479Ssklower m_freem(m); 46221479Ssklower return (error); 46321479Ssklower } 46421479Ssklower /*ARGSUSED*/ 46521479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 46621479Ssklower struct socket *so; 46721479Ssklower int req; 46821479Ssklower struct mbuf *m, *nam, *rights; 46921479Ssklower { 47021479Ssklower int error = 0; 47121479Ssklower struct nspcb *nsp = sotonspcb(so); 47221479Ssklower extern struct nspcb nsrawpcb; 47321479Ssklower 47421479Ssklower switch (req) { 47521479Ssklower 47621479Ssklower case PRU_ATTACH: 47721479Ssklower 47821699Ssklower if (!suser() || (nsp != NULL)) { 47921479Ssklower error = EINVAL; 48021479Ssklower break; 48121479Ssklower } 48221479Ssklower error = ns_pcballoc(so, &nsrawpcb); 48321479Ssklower if (error) 48421479Ssklower break; 48521479Ssklower error = soreserve(so, 2048, 2048); 48621479Ssklower if (error) 48721479Ssklower break; 48821479Ssklower nsp = sotonspcb(so); 48921479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 49021479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 49121479Ssklower break; 49221479Ssklower default: 49321479Ssklower error = idp_usrreq(so, req, m, nam, rights); 49421479Ssklower } 49523500Ssklower return (error); 49621479Ssklower } 49721479Ssklower 498