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*23500Ssklower * @(#)idp_usrreq.c 6.4 (Berkeley) 06/16/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 3421479Ssklower idp_input(m, nsp) 3521479Ssklower struct mbuf *m; 3621479Ssklower register struct nspcb *nsp; 3721479Ssklower { 3821479Ssklower register struct idp *idp = mtod(m, struct idp *); 3921699Ssklower if (nsp==0) 4021699Ssklower panic("Impossible idp_input"); 4121479Ssklower 4221479Ssklower /* 4321479Ssklower * Construct sockaddr format source address. 4421479Ssklower * Stuff source address and datagram in user buffer. 4521479Ssklower */ 4621479Ssklower idp_ns.sns_addr = idp->idp_sna; 4721479Ssklower nsp->nsp_rpt = idp->idp_pt; 4821479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 4921479Ssklower m->m_len -= sizeof (struct idp); 5021479Ssklower m->m_off += sizeof (struct idp); 5121479Ssklower } 5221479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 5321479Ssklower m, (struct mbuf *)0) == 0) 5421479Ssklower goto bad; 5521479Ssklower sorwakeup(nsp->nsp_socket); 5621479Ssklower return; 5721479Ssklower bad: 5821479Ssklower m_freem(m); 5921479Ssklower } 6021479Ssklower 6121479Ssklower idp_abort(nsp) 6221479Ssklower struct nspcb *nsp; 6321479Ssklower { 6421479Ssklower struct socket *so = nsp->nsp_socket; 6521479Ssklower 6621479Ssklower ns_pcbdisconnect(nsp); 6721479Ssklower soisdisconnected(so); 6821479Ssklower } 6921479Ssklower 7021479Ssklower idp_output(nsp, m0) 7121479Ssklower struct nspcb *nsp; 7221479Ssklower struct mbuf *m0; 7321479Ssklower { 7421479Ssklower register struct mbuf *m; 7521479Ssklower register struct idp *idp; 7621479Ssklower register struct socket *so; 7721479Ssklower register int len = 0; 7821479Ssklower register struct route *ro; 7921479Ssklower struct mbuf *mprev; 8021479Ssklower extern int idpcksum; 8121479Ssklower 8221479Ssklower /* 8321479Ssklower * Calculate data length. 8421479Ssklower */ 8521479Ssklower for (m = m0; m; m = m->m_next) { 8621479Ssklower mprev = m; 8721479Ssklower len += m->m_len; 8821479Ssklower } 8921479Ssklower /* 9021479Ssklower * Make sure packet is actually of even length. 9121479Ssklower */ 9221479Ssklower 9321479Ssklower if (len & 1) { 9421479Ssklower m = mprev; 9521479Ssklower if (m->m_len + m->m_off < MMAXOFF) { 9621479Ssklower m->m_len++; 9721479Ssklower } else { 9821479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 9921479Ssklower 10021699Ssklower if (m1 == 0) { 10121699Ssklower m_freem(m0); 10221699Ssklower return (ENOBUFS); 10321699Ssklower } 10421479Ssklower m1->m_len = 1; 10521479Ssklower m1->m_off = MMAXOFF - 1; 10621479Ssklower * mtod(m1, char *) = 0; 10721479Ssklower m->m_next = m1; 10821479Ssklower } 10921479Ssklower } 11021479Ssklower 11121479Ssklower /* 11221479Ssklower * Fill in mbuf with extended IDP header 11321479Ssklower * and addresses and length put into network format. 11421479Ssklower */ 11521479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 11621479Ssklower m = m0; 11721479Ssklower idp = mtod(m, struct idp *); 11821479Ssklower } else { 11921479Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 12021479Ssklower if (m == 0) { 12121479Ssklower m_freem(m0); 12221479Ssklower return (ENOBUFS); 12321479Ssklower } 12421479Ssklower m->m_off = MMAXOFF - sizeof (struct idp); 12521479Ssklower m->m_len = sizeof (struct idp); 12621479Ssklower m->m_next = m0; 12721479Ssklower idp = mtod(m, struct idp *); 12821479Ssklower idp->idp_tc = 0; 12921479Ssklower idp->idp_pt = nsp->nsp_dpt; 13021479Ssklower idp->idp_sna = nsp->nsp_laddr; 13121479Ssklower idp->idp_dna = nsp->nsp_faddr; 13221479Ssklower len += sizeof (struct idp); 13321479Ssklower } 13421479Ssklower 13521479Ssklower idp->idp_len = htons((u_short)len); 13621479Ssklower 13721479Ssklower if (idpcksum) { 13821479Ssklower idp->idp_sum = 0; 13921479Ssklower len = ((len - 1) | 1) + 1; 14021479Ssklower idp->idp_sum = ns_cksum(m, len); 14121479Ssklower } else 14221479Ssklower idp->idp_sum = 0xffff; 14321479Ssklower 14421479Ssklower /* 14521479Ssklower * Output datagram. 14621479Ssklower */ 14721479Ssklower so = nsp->nsp_socket; 14821479Ssklower if (so->so_options & SO_DONTROUTE) 14921479Ssklower return (ns_output(m, (struct route *)0, 15021479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 15121479Ssklower /* 15221479Ssklower * Use cached route for previous datagram if 15321479Ssklower * this is also to the same destination. 15421479Ssklower * 15521479Ssklower * NB: We don't handle broadcasts because that 15621479Ssklower * would require 3 subroutine calls. 15721479Ssklower */ 15821479Ssklower ro = &nsp->nsp_route; 15921479Ssklower if (ro->ro_rt && 16021479Ssklower ((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) && 16121479Ssklower !(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) { 16221479Ssklower RTFREE(ro->ro_rt); 16321479Ssklower ro->ro_rt = (struct rtentry *)0; 16421479Ssklower nsp->nsp_lastnet = idp->idp_dna.x_net; 16521479Ssklower } 16621479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 16721479Ssklower } 16821479Ssklower /*ARGSUSED*/ 16921479Ssklower idp_ctloutput(req, so, level, name, value) 17021479Ssklower int req, level; 17121479Ssklower struct socket *so; 17221479Ssklower int name; 17321479Ssklower struct mbuf **value; 17421479Ssklower { 17521479Ssklower register struct mbuf *m; 17621479Ssklower struct nspcb *nsp = sotonspcb(so); 17721479Ssklower int mask, error = 0; 17821479Ssklower 179*23500Ssklower if (nsp == NULL) 180*23500Ssklower return (EINVAL); 18121479Ssklower 18221479Ssklower switch (req) { 183*23500Ssklower 18421479Ssklower case PRCO_GETOPT: 185*23500Ssklower if (value==NULL) 186*23500Ssklower return (EINVAL); 18721479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 188*23500Ssklower if (m==NULL) 189*23500Ssklower return (ENOBUFS); 19021479Ssklower switch (name) { 191*23500Ssklower 19221479Ssklower case SO_HEADERS_ON_INPUT: 19321479Ssklower mask = NSP_RAWIN; 19421479Ssklower goto get_flags; 195*23500Ssklower 19621479Ssklower case SO_HEADERS_ON_OUTPUT: 19721479Ssklower mask = NSP_RAWOUT; 19821479Ssklower get_flags: 19921479Ssklower m->m_len = sizeof(short); 20021479Ssklower m->m_off = MMAXOFF - sizeof(short); 20121479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 20221479Ssklower break; 203*23500Ssklower 20421479Ssklower case SO_DEFAULT_HEADERS: 20521479Ssklower m->m_len = sizeof(struct idp); 20621479Ssklower m->m_off = MMAXOFF - sizeof(struct idp); 20721479Ssklower { 20821479Ssklower register struct idp *idp = mtod(m, struct idp *); 20921479Ssklower idp->idp_len = 0; 21021479Ssklower idp->idp_sum = 0; 21121479Ssklower idp->idp_tc = 0; 21221479Ssklower idp->idp_pt = nsp->nsp_dpt; 21321479Ssklower idp->idp_dna = nsp->nsp_faddr; 21421479Ssklower idp->idp_sna = nsp->nsp_laddr; 21521479Ssklower } 21621479Ssklower } 21721479Ssklower *value = m; 21821479Ssklower break; 219*23500Ssklower 22021479Ssklower case PRCO_SETOPT: 22121479Ssklower switch (name) { 22221479Ssklower int mask, *ok; 22321479Ssklower 22421479Ssklower case SO_HEADERS_ON_INPUT: 22521479Ssklower mask = NSP_RAWIN; 22621479Ssklower goto set_head; 227*23500Ssklower 22821479Ssklower case SO_HEADERS_ON_OUTPUT: 22921479Ssklower mask = NSP_RAWOUT; 23021479Ssklower set_head: 23121479Ssklower if (value && *value) { 23221479Ssklower ok = mtod(*value, int *); 23321479Ssklower if (*ok) 23421479Ssklower nsp->nsp_flags |= mask; 23521479Ssklower else 23621479Ssklower nsp->nsp_flags &= ~mask; 23721479Ssklower } else error = EINVAL; 23821479Ssklower break; 239*23500Ssklower 24021479Ssklower case SO_DEFAULT_HEADERS: 24121479Ssklower { 24221479Ssklower register struct idp *idp 24321479Ssklower = mtod(*value, struct idp *); 24421479Ssklower nsp->nsp_dpt = idp->idp_pt; 24521479Ssklower } 24621479Ssklower #ifdef NSIP 24721479Ssklower break; 248*23500Ssklower 24921479Ssklower case SO_NSIP_ROUTE: 25021479Ssklower error = nsip_route(*value); 25121479Ssklower #endif NSIP 25221479Ssklower } 25321479Ssklower if (value && *value) 25421479Ssklower m_freem(*value); 25521479Ssklower break; 25621479Ssklower } 257*23500Ssklower return (error); 25821479Ssklower } 25921479Ssklower 26021479Ssklower /*ARGSUSED*/ 26121479Ssklower idp_usrreq(so, req, m, nam, rights) 26221479Ssklower struct socket *so; 26321479Ssklower int req; 26421479Ssklower struct mbuf *m, *nam, *rights; 26521479Ssklower { 26621479Ssklower struct nspcb *nsp = sotonspcb(so); 26721479Ssklower int error = 0; 26821479Ssklower 26921479Ssklower if (req == PRU_CONTROL) 27021479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 27121479Ssklower (struct ifnet *)rights)); 27221479Ssklower if (rights && rights->m_len) { 27321479Ssklower error = EINVAL; 27421479Ssklower goto release; 27521479Ssklower } 27621479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 27721479Ssklower error = EINVAL; 27821479Ssklower goto release; 27921479Ssklower } 28021479Ssklower switch (req) { 28121479Ssklower 28221479Ssklower case PRU_ATTACH: 28321479Ssklower if (nsp != NULL) { 28421479Ssklower error = EINVAL; 28521479Ssklower break; 28621479Ssklower } 28721479Ssklower error = ns_pcballoc(so, &nspcb); 28821479Ssklower if (error) 28921479Ssklower break; 29021479Ssklower error = soreserve(so, 2048, 2048); 29121479Ssklower if (error) 29221479Ssklower break; 29321479Ssklower break; 29421479Ssklower 29521479Ssklower case PRU_DETACH: 29621479Ssklower if (nsp == NULL) { 29721479Ssklower error = ENOTCONN; 29821479Ssklower break; 29921479Ssklower } 30021479Ssklower ns_pcbdetach(nsp); 30121479Ssklower break; 30221479Ssklower 30321479Ssklower case PRU_BIND: 30421479Ssklower error = ns_pcbbind(nsp, nam); 30521479Ssklower break; 30621479Ssklower 30721479Ssklower case PRU_LISTEN: 30821479Ssklower error = EOPNOTSUPP; 30921479Ssklower break; 31021479Ssklower 31121479Ssklower case PRU_CONNECT: 31221479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 31321479Ssklower error = EISCONN; 31421479Ssklower break; 31521479Ssklower } 31621479Ssklower error = ns_pcbconnect(nsp, nam); 31721479Ssklower if (error == 0) 31821479Ssklower soisconnected(so); 31921479Ssklower break; 32021479Ssklower 32121479Ssklower case PRU_CONNECT2: 32221479Ssklower error = EOPNOTSUPP; 32321479Ssklower break; 32421479Ssklower 32521479Ssklower case PRU_ACCEPT: 32621479Ssklower error = EOPNOTSUPP; 32721479Ssklower break; 32821479Ssklower 32921479Ssklower case PRU_DISCONNECT: 33021479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 33121479Ssklower error = ENOTCONN; 33221479Ssklower break; 33321479Ssklower } 33421479Ssklower ns_pcbdisconnect(nsp); 33521479Ssklower soisdisconnected(so); 33621479Ssklower break; 33721479Ssklower 33821479Ssklower case PRU_SHUTDOWN: 33921479Ssklower socantsendmore(so); 34021479Ssklower break; 34121479Ssklower 34221479Ssklower case PRU_SEND: 34321479Ssklower { 34421479Ssklower struct ns_addr laddr; 34521479Ssklower int s; 34621479Ssklower 34721479Ssklower if (nam) { 34821479Ssklower laddr = nsp->nsp_laddr; 34921479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 35021479Ssklower error = EISCONN; 35121479Ssklower break; 35221479Ssklower } 35321479Ssklower /* 35421479Ssklower * Must block input while temporarily connected. 35521479Ssklower */ 35621479Ssklower s = splnet(); 35721479Ssklower error = ns_pcbconnect(nsp, nam); 35821479Ssklower if (error) { 35921479Ssklower splx(s); 36021479Ssklower break; 36121479Ssklower } 36221479Ssklower } else { 36321479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 36421479Ssklower error = ENOTCONN; 36521479Ssklower break; 36621479Ssklower } 36721479Ssklower } 36821479Ssklower error = idp_output(nsp, m); 36921479Ssklower m = NULL; 37021479Ssklower if (nam) { 37121479Ssklower ns_pcbdisconnect(nsp); 37221479Ssklower splx(s); 37321479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 37421479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 37521479Ssklower } 37621479Ssklower } 37721479Ssklower break; 37821479Ssklower 37921479Ssklower case PRU_ABORT: 38021479Ssklower ns_pcbdetach(nsp); 38121479Ssklower sofree(so); 38221479Ssklower soisdisconnected(so); 38321479Ssklower break; 38421479Ssklower 38521479Ssklower case PRU_SOCKADDR: 38621479Ssklower ns_setsockaddr(nsp, nam); 38721479Ssklower break; 38821479Ssklower 38921479Ssklower case PRU_PEERADDR: 39021479Ssklower ns_setpeeraddr(nsp, nam); 39121479Ssklower break; 39221479Ssklower 39321479Ssklower case PRU_SENSE: 39421479Ssklower /* 39521479Ssklower * stat: don't bother with a blocksize. 39621479Ssklower */ 39721479Ssklower return (0); 39821479Ssklower 39921479Ssklower case PRU_SENDOOB: 40021479Ssklower case PRU_FASTTIMO: 40121479Ssklower case PRU_SLOWTIMO: 40221479Ssklower case PRU_PROTORCV: 40321479Ssklower case PRU_PROTOSEND: 40421479Ssklower error = EOPNOTSUPP; 40521479Ssklower break; 40621479Ssklower 40721479Ssklower case PRU_CONTROL: 40821479Ssklower case PRU_RCVD: 40921479Ssklower case PRU_RCVOOB: 41021479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 41121479Ssklower 41221479Ssklower default: 41321479Ssklower panic("idp_usrreq"); 41421479Ssklower } 41521479Ssklower release: 41621479Ssklower if (m != NULL) 41721479Ssklower m_freem(m); 41821479Ssklower return (error); 41921479Ssklower } 42021479Ssklower /*ARGSUSED*/ 42121479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 42221479Ssklower struct socket *so; 42321479Ssklower int req; 42421479Ssklower struct mbuf *m, *nam, *rights; 42521479Ssklower { 42621479Ssklower int error = 0; 42721479Ssklower struct nspcb *nsp = sotonspcb(so); 42821479Ssklower extern struct nspcb nsrawpcb; 42921479Ssklower 43021479Ssklower switch (req) { 43121479Ssklower 43221479Ssklower case PRU_ATTACH: 43321479Ssklower 43421699Ssklower if (!suser() || (nsp != NULL)) { 43521479Ssklower error = EINVAL; 43621479Ssklower break; 43721479Ssklower } 43821479Ssklower error = ns_pcballoc(so, &nsrawpcb); 43921479Ssklower if (error) 44021479Ssklower break; 44121479Ssklower error = soreserve(so, 2048, 2048); 44221479Ssklower if (error) 44321479Ssklower break; 44421479Ssklower nsp = sotonspcb(so); 44521479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 44621479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 44721479Ssklower break; 44821479Ssklower default: 44921479Ssklower error = idp_usrreq(so, req, m, nam, rights); 45021479Ssklower } 451*23500Ssklower return (error); 45221479Ssklower } 45321479Ssklower 454