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