123202Smckusick /* 233371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 333371Ssklower * All rights reserved. 423202Smckusick * 533371Ssklower * Redistribution and use in source and binary forms are permitted 634856Sbostic * provided that the above copyright notice and this paragraph are 734856Sbostic * duplicated in all such forms and that any documentation, 834856Sbostic * advertising materials, and other materials related to such 934856Sbostic * distribution and use acknowledge that the software was developed 1034856Sbostic * by the University of California, Berkeley. The name of the 1134856Sbostic * University may not be used to endorse or promote products derived 1234856Sbostic * from this software without specific prior written permission. 1334856Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434856Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534856Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633371Ssklower * 17*37546Smckusick * @(#)idp_usrreq.c 7.7 (Berkeley) 04/26/89 1823202Smckusick */ 1921479Ssklower 2021479Ssklower #include "param.h" 2121479Ssklower #include "dir.h" 2221479Ssklower #include "user.h" 2335797Ssklower #include "malloc.h" 2421479Ssklower #include "mbuf.h" 2521479Ssklower #include "protosw.h" 2621479Ssklower #include "socket.h" 2721479Ssklower #include "socketvar.h" 2821479Ssklower #include "errno.h" 2921479Ssklower #include "stat.h" 3021479Ssklower 3121479Ssklower #include "../net/if.h" 3221479Ssklower #include "../net/route.h" 3321479Ssklower 3421479Ssklower #include "ns.h" 3521479Ssklower #include "ns_pcb.h" 3624611Ssklower #include "ns_if.h" 3721479Ssklower #include "idp.h" 3821479Ssklower #include "idp_var.h" 3921479Ssklower #include "ns_error.h" 4021479Ssklower 4121479Ssklower /* 4221479Ssklower * IDP protocol implementation. 4321479Ssklower */ 4421479Ssklower 4537473Ssklower struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS }; 4621479Ssklower 4723977Ssklower /* 4823977Ssklower * This may also be called for raw listeners. 4923977Ssklower */ 5035797Ssklower idp_input(m, nsp) 5121479Ssklower struct mbuf *m; 5221479Ssklower register struct nspcb *nsp; 5321479Ssklower { 5421479Ssklower register struct idp *idp = mtod(m, struct idp *); 5535797Ssklower struct ifnet *ifp = m->m_pkthdr.rcvif; 5621479Ssklower 5724611Ssklower if (nsp==0) 5824049Ssklower panic("No nspcb"); 5921479Ssklower /* 6021479Ssklower * Construct sockaddr format source address. 6121479Ssklower * Stuff source address and datagram in user buffer. 6221479Ssklower */ 6321479Ssklower idp_ns.sns_addr = idp->idp_sna; 6426055Ssklower if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { 6537473Ssklower register struct ifaddr *ifa; 6624611Ssklower 6737473Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 6837473Ssklower if (ifa->ifa_addr->sa_family == AF_NS) { 6924611Ssklower idp_ns.sns_addr.x_net = 7037473Ssklower IA_SNS(ifa)->sns_addr.x_net; 7124611Ssklower break; 7224611Ssklower } 7324611Ssklower } 7424611Ssklower } 7521479Ssklower nsp->nsp_rpt = idp->idp_pt; 7621479Ssklower if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 7721479Ssklower m->m_len -= sizeof (struct idp); 7835797Ssklower m->m_pkthdr.len -= sizeof (struct idp); 7935797Ssklower m->m_data += sizeof (struct idp); 8021479Ssklower } 8121479Ssklower if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 8221479Ssklower m, (struct mbuf *)0) == 0) 8321479Ssklower goto bad; 8421479Ssklower sorwakeup(nsp->nsp_socket); 8521479Ssklower return; 8621479Ssklower bad: 8721479Ssklower m_freem(m); 8821479Ssklower } 8921479Ssklower 9021479Ssklower idp_abort(nsp) 9121479Ssklower struct nspcb *nsp; 9221479Ssklower { 9321479Ssklower struct socket *so = nsp->nsp_socket; 9421479Ssklower 9521479Ssklower ns_pcbdisconnect(nsp); 9621479Ssklower soisdisconnected(so); 9721479Ssklower } 9823977Ssklower /* 9923977Ssklower * Drop connection, reporting 10023977Ssklower * the specified error. 10123977Ssklower */ 10223977Ssklower struct nspcb * 10323977Ssklower idp_drop(nsp, errno) 10423977Ssklower register struct nspcb *nsp; 10523977Ssklower int errno; 10623977Ssklower { 10723977Ssklower struct socket *so = nsp->nsp_socket; 10821479Ssklower 10923977Ssklower /* 11023977Ssklower * someday, in the xerox world 11123977Ssklower * we will generate error protocol packets 11223977Ssklower * announcing that the socket has gone away. 11323977Ssklower */ 11423977Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 11523977Ssklower tp->t_state = TCPS_CLOSED; 11623977Ssklower (void) tcp_output(tp); 11723977Ssklower }*/ 11823977Ssklower so->so_error = errno; 11923977Ssklower ns_pcbdisconnect(nsp); 12023977Ssklower soisdisconnected(so); 12123977Ssklower } 12223977Ssklower 12325042Ssklower int noIdpRoute; 12421479Ssklower idp_output(nsp, m0) 12521479Ssklower struct nspcb *nsp; 12621479Ssklower struct mbuf *m0; 12721479Ssklower { 12821479Ssklower register struct mbuf *m; 12921479Ssklower register struct idp *idp; 13021479Ssklower register struct socket *so; 13121479Ssklower register int len = 0; 13221479Ssklower register struct route *ro; 13321479Ssklower struct mbuf *mprev; 13421479Ssklower extern int idpcksum; 13521479Ssklower 13621479Ssklower /* 13721479Ssklower * Calculate data length. 13821479Ssklower */ 13921479Ssklower for (m = m0; m; m = m->m_next) { 14021479Ssklower mprev = m; 14121479Ssklower len += m->m_len; 14221479Ssklower } 14321479Ssklower /* 14421479Ssklower * Make sure packet is actually of even length. 14521479Ssklower */ 14621479Ssklower 14721479Ssklower if (len & 1) { 14821479Ssklower m = mprev; 14935797Ssklower if ((m->m_flags & M_EXT) == 0 && 15035797Ssklower (m->m_len + m->m_data < &m->m_dat[MLEN])) { 15121479Ssklower m->m_len++; 15221479Ssklower } else { 15321479Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 15421479Ssklower 15521699Ssklower if (m1 == 0) { 15621699Ssklower m_freem(m0); 15721699Ssklower return (ENOBUFS); 15821699Ssklower } 15921479Ssklower m1->m_len = 1; 16021479Ssklower * mtod(m1, char *) = 0; 16121479Ssklower m->m_next = m1; 16221479Ssklower } 16335797Ssklower m0->m_pkthdr.len++; 16421479Ssklower } 16521479Ssklower 16621479Ssklower /* 16721479Ssklower * Fill in mbuf with extended IDP header 16821479Ssklower * and addresses and length put into network format. 16921479Ssklower */ 17035797Ssklower m = m0; 17121479Ssklower if (nsp->nsp_flags & NSP_RAWOUT) { 17221479Ssklower idp = mtod(m, struct idp *); 17321479Ssklower } else { 17435797Ssklower M_PREPEND(m, sizeof (struct idp), M_DONTWAIT); 17535797Ssklower if (m == 0) 17621479Ssklower return (ENOBUFS); 17721479Ssklower idp = mtod(m, struct idp *); 17821479Ssklower idp->idp_tc = 0; 17921479Ssklower idp->idp_pt = nsp->nsp_dpt; 18021479Ssklower idp->idp_sna = nsp->nsp_laddr; 18121479Ssklower idp->idp_dna = nsp->nsp_faddr; 18221479Ssklower len += sizeof (struct idp); 18321479Ssklower } 18421479Ssklower 18521479Ssklower idp->idp_len = htons((u_short)len); 18621479Ssklower 18721479Ssklower if (idpcksum) { 18821479Ssklower idp->idp_sum = 0; 18921479Ssklower len = ((len - 1) | 1) + 1; 19021479Ssklower idp->idp_sum = ns_cksum(m, len); 19121479Ssklower } else 19221479Ssklower idp->idp_sum = 0xffff; 19321479Ssklower 19421479Ssklower /* 19521479Ssklower * Output datagram. 19621479Ssklower */ 19721479Ssklower so = nsp->nsp_socket; 19821479Ssklower if (so->so_options & SO_DONTROUTE) 19921479Ssklower return (ns_output(m, (struct route *)0, 20021479Ssklower (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 20121479Ssklower /* 20221479Ssklower * Use cached route for previous datagram if 20325042Ssklower * possible. If the previous net was the same 20425042Ssklower * and the interface was a broadcast medium, or 20525042Ssklower * if the previous destination was identical, 20625042Ssklower * then we are ok. 20721479Ssklower * 20821479Ssklower * NB: We don't handle broadcasts because that 20921479Ssklower * would require 3 subroutine calls. 21021479Ssklower */ 21121479Ssklower ro = &nsp->nsp_route; 21225042Ssklower #ifdef ancient_history 21325042Ssklower /* 21425042Ssklower * I think that this will all be handled in ns_pcbconnect! 21525042Ssklower */ 21625042Ssklower if (ro->ro_rt) { 21725042Ssklower if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { 21825042Ssklower /* 21925042Ssklower * This assumes we have no GH type routes 22025042Ssklower */ 22125042Ssklower if (ro->ro_rt->rt_flags & RTF_HOST) { 22225042Ssklower if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) 22325042Ssklower goto re_route; 22425042Ssklower 22525042Ssklower } 22625042Ssklower if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 22725042Ssklower register struct ns_addr *dst = 22825042Ssklower &satons_addr(ro->ro_dst); 22925042Ssklower dst->x_host = idp->idp_dna.x_host; 23025042Ssklower } 23125042Ssklower /* 23225042Ssklower * Otherwise, we go through the same gateway 23325042Ssklower * and dst is already set up. 23425042Ssklower */ 23525042Ssklower } else { 23625042Ssklower re_route: 23725042Ssklower RTFREE(ro->ro_rt); 23825042Ssklower ro->ro_rt = (struct rtentry *)0; 23925042Ssklower } 24021479Ssklower } 24125042Ssklower nsp->nsp_lastdst = idp->idp_dna; 24225042Ssklower #endif ancient_history 24325042Ssklower if (noIdpRoute) ro = 0; 24421479Ssklower return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 24521479Ssklower } 24624225Ssklower /* ARGSUSED */ 24721479Ssklower idp_ctloutput(req, so, level, name, value) 24821479Ssklower int req, level; 24921479Ssklower struct socket *so; 25021479Ssklower int name; 25121479Ssklower struct mbuf **value; 25221479Ssklower { 25321479Ssklower register struct mbuf *m; 25421479Ssklower struct nspcb *nsp = sotonspcb(so); 25521479Ssklower int mask, error = 0; 25623977Ssklower extern long ns_pexseq; 25721479Ssklower 25823500Ssklower if (nsp == NULL) 25923500Ssklower return (EINVAL); 26021479Ssklower 26121479Ssklower switch (req) { 26223500Ssklower 26321479Ssklower case PRCO_GETOPT: 26423500Ssklower if (value==NULL) 26523500Ssklower return (EINVAL); 26621479Ssklower m = m_get(M_DONTWAIT, MT_DATA); 26723500Ssklower if (m==NULL) 26823500Ssklower return (ENOBUFS); 26921479Ssklower switch (name) { 27023500Ssklower 27124049Ssklower case SO_ALL_PACKETS: 27224049Ssklower mask = NSP_ALL_PACKETS; 27324049Ssklower goto get_flags; 27424049Ssklower 27521479Ssklower case SO_HEADERS_ON_INPUT: 27621479Ssklower mask = NSP_RAWIN; 27721479Ssklower goto get_flags; 27823500Ssklower 27921479Ssklower case SO_HEADERS_ON_OUTPUT: 28021479Ssklower mask = NSP_RAWOUT; 28121479Ssklower get_flags: 28221479Ssklower m->m_len = sizeof(short); 28321479Ssklower *mtod(m, short *) = nsp->nsp_flags & mask; 28421479Ssklower break; 28523500Ssklower 28621479Ssklower case SO_DEFAULT_HEADERS: 28721479Ssklower m->m_len = sizeof(struct idp); 28821479Ssklower { 28921479Ssklower register struct idp *idp = mtod(m, struct idp *); 29021479Ssklower idp->idp_len = 0; 29121479Ssklower idp->idp_sum = 0; 29221479Ssklower idp->idp_tc = 0; 29321479Ssklower idp->idp_pt = nsp->nsp_dpt; 29421479Ssklower idp->idp_dna = nsp->nsp_faddr; 29521479Ssklower idp->idp_sna = nsp->nsp_laddr; 29621479Ssklower } 29723977Ssklower break; 29823977Ssklower 29923977Ssklower case SO_SEQNO: 30023977Ssklower m->m_len = sizeof(long); 30123977Ssklower *mtod(m, long *) = ns_pexseq++; 30225335Ssklower break; 30325335Ssklower 30425335Ssklower default: 30525335Ssklower error = EINVAL; 30621479Ssklower } 30721479Ssklower *value = m; 30821479Ssklower break; 30923500Ssklower 31021479Ssklower case PRCO_SETOPT: 31121479Ssklower switch (name) { 31224225Ssklower int *ok; 31321479Ssklower 31424049Ssklower case SO_ALL_PACKETS: 31524049Ssklower mask = NSP_ALL_PACKETS; 31624049Ssklower goto set_head; 31724049Ssklower 31821479Ssklower case SO_HEADERS_ON_INPUT: 31921479Ssklower mask = NSP_RAWIN; 32021479Ssklower goto set_head; 32123500Ssklower 32221479Ssklower case SO_HEADERS_ON_OUTPUT: 32321479Ssklower mask = NSP_RAWOUT; 32421479Ssklower set_head: 32521479Ssklower if (value && *value) { 32621479Ssklower ok = mtod(*value, int *); 32721479Ssklower if (*ok) 32821479Ssklower nsp->nsp_flags |= mask; 32921479Ssklower else 33021479Ssklower nsp->nsp_flags &= ~mask; 33121479Ssklower } else error = EINVAL; 33221479Ssklower break; 33323500Ssklower 33421479Ssklower case SO_DEFAULT_HEADERS: 33521479Ssklower { 33621479Ssklower register struct idp *idp 33721479Ssklower = mtod(*value, struct idp *); 33821479Ssklower nsp->nsp_dpt = idp->idp_pt; 33921479Ssklower } 34025335Ssklower break; 34121479Ssklower #ifdef NSIP 34223500Ssklower 34321479Ssklower case SO_NSIP_ROUTE: 34421479Ssklower error = nsip_route(*value); 34525335Ssklower break; 34621479Ssklower #endif NSIP 34725335Ssklower default: 34825335Ssklower error = EINVAL; 34921479Ssklower } 35021479Ssklower if (value && *value) 35121479Ssklower m_freem(*value); 35221479Ssklower break; 35321479Ssklower } 35423500Ssklower return (error); 35521479Ssklower } 35621479Ssklower 35721479Ssklower /*ARGSUSED*/ 35821479Ssklower idp_usrreq(so, req, m, nam, rights) 35921479Ssklower struct socket *so; 36021479Ssklower int req; 36121479Ssklower struct mbuf *m, *nam, *rights; 36221479Ssklower { 36321479Ssklower struct nspcb *nsp = sotonspcb(so); 36421479Ssklower int error = 0; 36521479Ssklower 36621479Ssklower if (req == PRU_CONTROL) 36721479Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 36821479Ssklower (struct ifnet *)rights)); 36921479Ssklower if (rights && rights->m_len) { 37021479Ssklower error = EINVAL; 37121479Ssklower goto release; 37221479Ssklower } 37321479Ssklower if (nsp == NULL && req != PRU_ATTACH) { 37421479Ssklower error = EINVAL; 37521479Ssklower goto release; 37621479Ssklower } 37721479Ssklower switch (req) { 37821479Ssklower 37921479Ssklower case PRU_ATTACH: 38021479Ssklower if (nsp != NULL) { 38121479Ssklower error = EINVAL; 38221479Ssklower break; 38321479Ssklower } 38421479Ssklower error = ns_pcballoc(so, &nspcb); 38521479Ssklower if (error) 38621479Ssklower break; 38734500Skarels error = soreserve(so, (u_long) 2048, (u_long) 2048); 38821479Ssklower if (error) 38921479Ssklower break; 39021479Ssklower break; 39121479Ssklower 39221479Ssklower case PRU_DETACH: 39321479Ssklower if (nsp == NULL) { 39421479Ssklower error = ENOTCONN; 39521479Ssklower break; 39621479Ssklower } 39721479Ssklower ns_pcbdetach(nsp); 39821479Ssklower break; 39921479Ssklower 40021479Ssklower case PRU_BIND: 40121479Ssklower error = ns_pcbbind(nsp, nam); 40221479Ssklower break; 40321479Ssklower 40421479Ssklower case PRU_LISTEN: 40521479Ssklower error = EOPNOTSUPP; 40621479Ssklower break; 40721479Ssklower 40821479Ssklower case PRU_CONNECT: 40921479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 41021479Ssklower error = EISCONN; 41121479Ssklower break; 41221479Ssklower } 41321479Ssklower error = ns_pcbconnect(nsp, nam); 41421479Ssklower if (error == 0) 41521479Ssklower soisconnected(so); 41621479Ssklower break; 41721479Ssklower 41821479Ssklower case PRU_CONNECT2: 41921479Ssklower error = EOPNOTSUPP; 42021479Ssklower break; 42121479Ssklower 42221479Ssklower case PRU_ACCEPT: 42321479Ssklower error = EOPNOTSUPP; 42421479Ssklower break; 42521479Ssklower 42621479Ssklower case PRU_DISCONNECT: 42721479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 42821479Ssklower error = ENOTCONN; 42921479Ssklower break; 43021479Ssklower } 43121479Ssklower ns_pcbdisconnect(nsp); 43221479Ssklower soisdisconnected(so); 43321479Ssklower break; 43421479Ssklower 43521479Ssklower case PRU_SHUTDOWN: 43621479Ssklower socantsendmore(so); 43721479Ssklower break; 43821479Ssklower 43921479Ssklower case PRU_SEND: 44021479Ssklower { 44121479Ssklower struct ns_addr laddr; 44221479Ssklower int s; 44321479Ssklower 44421479Ssklower if (nam) { 44521479Ssklower laddr = nsp->nsp_laddr; 44621479Ssklower if (!ns_nullhost(nsp->nsp_faddr)) { 44721479Ssklower error = EISCONN; 44821479Ssklower break; 44921479Ssklower } 45021479Ssklower /* 45121479Ssklower * Must block input while temporarily connected. 45221479Ssklower */ 45321479Ssklower s = splnet(); 45421479Ssklower error = ns_pcbconnect(nsp, nam); 45521479Ssklower if (error) { 45621479Ssklower splx(s); 45721479Ssklower break; 45821479Ssklower } 45921479Ssklower } else { 46021479Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 46121479Ssklower error = ENOTCONN; 46221479Ssklower break; 46321479Ssklower } 46421479Ssklower } 46521479Ssklower error = idp_output(nsp, m); 46621479Ssklower m = NULL; 46721479Ssklower if (nam) { 46821479Ssklower ns_pcbdisconnect(nsp); 46921479Ssklower splx(s); 47021479Ssklower nsp->nsp_laddr.x_host = laddr.x_host; 47121479Ssklower nsp->nsp_laddr.x_port = laddr.x_port; 47221479Ssklower } 47321479Ssklower } 47421479Ssklower break; 47521479Ssklower 47621479Ssklower case PRU_ABORT: 47721479Ssklower ns_pcbdetach(nsp); 47821479Ssklower sofree(so); 47921479Ssklower soisdisconnected(so); 48021479Ssklower break; 48121479Ssklower 48221479Ssklower case PRU_SOCKADDR: 48321479Ssklower ns_setsockaddr(nsp, nam); 48421479Ssklower break; 48521479Ssklower 48621479Ssklower case PRU_PEERADDR: 48721479Ssklower ns_setpeeraddr(nsp, nam); 48821479Ssklower break; 48921479Ssklower 49021479Ssklower case PRU_SENSE: 49121479Ssklower /* 49221479Ssklower * stat: don't bother with a blocksize. 49321479Ssklower */ 49421479Ssklower return (0); 49521479Ssklower 49621479Ssklower case PRU_SENDOOB: 49721479Ssklower case PRU_FASTTIMO: 49821479Ssklower case PRU_SLOWTIMO: 49921479Ssklower case PRU_PROTORCV: 50021479Ssklower case PRU_PROTOSEND: 50121479Ssklower error = EOPNOTSUPP; 50221479Ssklower break; 50321479Ssklower 50421479Ssklower case PRU_CONTROL: 50521479Ssklower case PRU_RCVD: 50621479Ssklower case PRU_RCVOOB: 50721479Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 50821479Ssklower 50921479Ssklower default: 51021479Ssklower panic("idp_usrreq"); 51121479Ssklower } 51221479Ssklower release: 51321479Ssklower if (m != NULL) 51421479Ssklower m_freem(m); 51521479Ssklower return (error); 51621479Ssklower } 51721479Ssklower /*ARGSUSED*/ 51821479Ssklower idp_raw_usrreq(so, req, m, nam, rights) 51921479Ssklower struct socket *so; 52021479Ssklower int req; 52121479Ssklower struct mbuf *m, *nam, *rights; 52221479Ssklower { 52321479Ssklower int error = 0; 52421479Ssklower struct nspcb *nsp = sotonspcb(so); 52521479Ssklower extern struct nspcb nsrawpcb; 52621479Ssklower 52721479Ssklower switch (req) { 52821479Ssklower 52921479Ssklower case PRU_ATTACH: 53021479Ssklower 531*37546Smckusick if (suser(u.u_cred, &u.u_acflag) || (nsp != NULL)) { 53221479Ssklower error = EINVAL; 53321479Ssklower break; 53421479Ssklower } 53521479Ssklower error = ns_pcballoc(so, &nsrawpcb); 53621479Ssklower if (error) 53721479Ssklower break; 53834500Skarels error = soreserve(so, (u_long) 2048, (u_long) 2048); 53921479Ssklower if (error) 54021479Ssklower break; 54121479Ssklower nsp = sotonspcb(so); 54221479Ssklower nsp->nsp_faddr.x_host = ns_broadhost; 54321479Ssklower nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 54421479Ssklower break; 54521479Ssklower default: 54621479Ssklower error = idp_usrreq(so, req, m, nam, rights); 54721479Ssklower } 54823500Ssklower return (error); 54921479Ssklower } 55021479Ssklower 551