139540Ssklower /* 239540Ssklower * Copyright (c) 1989 Regents of the University of California. 339540Ssklower * All rights reserved. 439540Ssklower * 544495Sbostic * %sccs.include.redist.c% 639540Ssklower * 7*50432Ssklower * @(#)cltp_usrreq.c 7.7 (Berkeley) 07/18/91 839540Ssklower */ 939540Ssklower 1039540Ssklower #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ 1139540Ssklower #include "param.h" 1239540Ssklower #include "malloc.h" 1339540Ssklower #include "mbuf.h" 1439540Ssklower #include "protosw.h" 1539540Ssklower #include "socket.h" 1639540Ssklower #include "socketvar.h" 1739540Ssklower #include "errno.h" 1839540Ssklower #include "stat.h" 1939540Ssklower 2039540Ssklower #include "../net/if.h" 2139540Ssklower #include "../net/route.h" 2239540Ssklower 2339540Ssklower #include "argo_debug.h" 2439540Ssklower #include "iso.h" 2539540Ssklower #include "iso_pcb.h" 2639540Ssklower #include "iso_var.h" 2739540Ssklower #include "clnp.h" 2839540Ssklower #include "cltp_var.h" 2939540Ssklower #endif 3039540Ssklower 3139540Ssklower /* 3239540Ssklower * CLTP protocol implementation. 3339540Ssklower * Per ISO 8602, December, 1987. 3439540Ssklower */ 3539540Ssklower cltp_init() 3639540Ssklower { 3739540Ssklower 3839540Ssklower cltb.isop_next = cltb.isop_prev = &cltb; 3939540Ssklower } 4039540Ssklower 4139540Ssklower int cltp_cksum = 1; 4239540Ssklower 4339540Ssklower 4439540Ssklower /* ARGUSED */ 4539540Ssklower cltp_input(m0, srcsa, dstsa, cons_channel, output) 4639540Ssklower struct mbuf *m0; 4739540Ssklower struct sockaddr *srcsa, *dstsa; 4839540Ssklower u_int cons_channel; 4939540Ssklower int (*output)(); 5039540Ssklower { 5139540Ssklower register struct isopcb *isop; 5239540Ssklower register struct mbuf *m = m0; 5339540Ssklower register u_char *up = mtod(m, u_char *); 5439540Ssklower register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa; 5539540Ssklower int len, hdrlen = *up + 1, dlen = 0; 5639540Ssklower u_char *uplim = up + hdrlen; 5739540Ssklower caddr_t dtsap; 5839540Ssklower 5939540Ssklower for (len = 0; m; m = m->m_next) 6039540Ssklower len += m->m_len; 6139540Ssklower up += 2; /* skip header */ 6239540Ssklower while (up < uplim) switch (*up) { /* process options */ 6339540Ssklower case CLTPOVAL_SRC: 6439540Ssklower src->siso_tlen = up[1]; 6539540Ssklower src->siso_len = up[1] + TSEL(src) - (caddr_t)src; 6639540Ssklower if (src->siso_len < sizeof(*src)) 6739540Ssklower src->siso_len = sizeof(*src); 6839540Ssklower else if (src->siso_len > sizeof(*src)) { 6939540Ssklower MGET(m, M_DONTWAIT, MT_SONAME); 7039540Ssklower if (m == 0) 7139540Ssklower goto bad; 7239540Ssklower m->m_len = src->siso_len; 7339540Ssklower src = mtod(m, struct sockaddr_iso *); 7439540Ssklower bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len); 7539540Ssklower } 7639540Ssklower bcopy((caddr_t)up + 2, TSEL(src), up[1]); 7739540Ssklower up += 2 + src->siso_tlen; 7839540Ssklower continue; 7939540Ssklower 8039540Ssklower case CLTPOVAL_DST: 8139540Ssklower dtsap = 2 + (caddr_t)up; 8239540Ssklower dlen = up[1]; 8339540Ssklower up += 2 + dlen; 8439540Ssklower continue; 8539540Ssklower 8639540Ssklower case CLTPOVAL_CSM: 8739925Ssklower if (iso_check_csum(m0, len)) { 8839925Ssklower cltpstat.cltps_badsum++; 8939540Ssklower goto bad; 9039925Ssklower } 9139540Ssklower up += 4; 9239925Ssklower continue; 9339540Ssklower 9439540Ssklower default: 9539540Ssklower printf("clts: unknown option (%x)\n", up[0]); 9639925Ssklower cltpstat.cltps_hdrops++; 9739540Ssklower goto bad; 9839540Ssklower } 9939540Ssklower if (dlen == 0 || src->siso_tlen == 0) 10039540Ssklower goto bad; 10139540Ssklower for (isop = cltb.isop_next;; isop = isop->isop_next) { 10239925Ssklower if (isop == &cltb) { 10339925Ssklower cltpstat.cltps_noport++; 10439540Ssklower goto bad; 10539925Ssklower } 10639540Ssklower if (isop->isop_laddr && 10739540Ssklower bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) 10839540Ssklower break; 10939540Ssklower } 11039540Ssklower m = m0; 11139925Ssklower m->m_len -= hdrlen; 11239925Ssklower m->m_data += hdrlen; 11339540Ssklower if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, 11439540Ssklower m, (struct mbuf *)0) == 0) 11539540Ssklower goto bad; 11639925Ssklower cltpstat.cltps_ipackets++; 11739540Ssklower sorwakeup(isop->isop_socket); 11839540Ssklower m0 = 0; 11939540Ssklower bad: 12039540Ssklower if (src != (struct sockaddr_iso *)srcsa) 12139540Ssklower m_freem(dtom(src)); 12239540Ssklower if (m0) 12339540Ssklower m_freem(m0); 12439925Ssklower return 0; 12539540Ssklower } 12639540Ssklower 12739540Ssklower /* 12839540Ssklower * Notify a cltp user of an asynchronous error; 12939540Ssklower * just wake up so that he can collect error status. 13039540Ssklower */ 13139540Ssklower cltp_notify(isop) 13239540Ssklower register struct isopcb *isop; 13339540Ssklower { 13439540Ssklower 13539540Ssklower sorwakeup(isop->isop_socket); 13639540Ssklower sowwakeup(isop->isop_socket); 13739540Ssklower } 13839540Ssklower 13939540Ssklower cltp_ctlinput(cmd, sa) 14039540Ssklower int cmd; 14139540Ssklower struct sockaddr *sa; 14239540Ssklower { 14339540Ssklower extern u_char inetctlerrmap[]; 14439540Ssklower struct sockaddr_iso *siso; 14539540Ssklower int iso_rtchange(); 14639540Ssklower 14739540Ssklower if ((unsigned)cmd > PRC_NCMDS) 14839540Ssklower return; 14939540Ssklower if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) 15039540Ssklower return; 15139540Ssklower siso = (struct sockaddr_iso *)sa; 15239540Ssklower if (siso == 0 || siso->siso_nlen == 0) 15339540Ssklower return; 15439540Ssklower 15539540Ssklower switch (cmd) { 15639540Ssklower case PRC_ROUTEDEAD: 15739540Ssklower case PRC_REDIRECT_NET: 15839540Ssklower case PRC_REDIRECT_HOST: 15939540Ssklower case PRC_REDIRECT_TOSNET: 16039540Ssklower case PRC_REDIRECT_TOSHOST: 16139540Ssklower iso_pcbnotify(&cltb, siso, 16239540Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 16339540Ssklower break; 16439540Ssklower 16539540Ssklower default: 16639540Ssklower if (inetctlerrmap[cmd] == 0) 16739540Ssklower return; /* XXX */ 16839540Ssklower iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], 16939540Ssklower cltp_notify); 17039540Ssklower } 17139540Ssklower } 17239540Ssklower 17339540Ssklower cltp_output(isop, m) 17439540Ssklower register struct isopcb *isop; 17539540Ssklower register struct mbuf *m; 17639540Ssklower { 17739540Ssklower register int len; 17839540Ssklower register struct sockaddr_iso *siso; 17939540Ssklower int hdrlen, error = 0, docsum; 18039540Ssklower register u_char *up; 18139540Ssklower 18239540Ssklower if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { 18339540Ssklower error = ENOTCONN; 18439540Ssklower goto bad; 18539540Ssklower } 18639540Ssklower /* 18739540Ssklower * Calculate data length and get a mbuf for CLTP header. 18839540Ssklower */ 18939540Ssklower hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen 19039540Ssklower + 2 + isop->isop_faddr->siso_tlen; 19139540Ssklower if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) 19239540Ssklower hdrlen += 4; 19339540Ssklower M_PREPEND(m, hdrlen, M_WAIT); 19439540Ssklower len = m->m_pkthdr.len; 19539540Ssklower /* 19639540Ssklower * Fill in mbuf with extended CLTP header 19739540Ssklower */ 19839540Ssklower up = mtod(m, u_char *); 19939925Ssklower up[0] = hdrlen - 1; 20039925Ssklower up[1] = UD_TPDU_type; 20139925Ssklower up[2] = CLTPOVAL_SRC; 20239540Ssklower up[3] = (siso = isop->isop_laddr)->siso_tlen; 20339540Ssklower up += 4; 20439540Ssklower bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 20539540Ssklower up += siso->siso_tlen; 20639925Ssklower up[0] = CLTPOVAL_DST; 20739540Ssklower up[1] = (siso = isop->isop_faddr)->siso_tlen; 20839540Ssklower up += 2; 20939540Ssklower bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 21039540Ssklower /* 21139540Ssklower * Stuff checksum and output datagram. 21239540Ssklower */ 21339540Ssklower if (docsum) { 21439540Ssklower up += siso->siso_tlen; 21539540Ssklower up[0] = CLTPOVAL_CSM; 21639540Ssklower up[1] = 2; 21739925Ssklower iso_gen_csum(m, 2 + up - mtod(m, u_char *), len); 21839540Ssklower } 21939925Ssklower cltpstat.cltps_opackets++; 22039540Ssklower return (tpclnp_output(isop, m, len, !docsum)); 22139540Ssklower bad: 22239540Ssklower m_freem(m); 22339540Ssklower return (error); 22439540Ssklower } 22539540Ssklower 22639540Ssklower u_long cltp_sendspace = 9216; /* really max datagram size */ 22739540Ssklower u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); 22839540Ssklower /* 40 1K datagrams */ 22939540Ssklower 23039540Ssklower 23139540Ssklower /*ARGSUSED*/ 23240771Ssklower cltp_usrreq(so, req, m, nam, control) 23339540Ssklower struct socket *so; 23439540Ssklower int req; 23540771Ssklower struct mbuf *m, *nam, *control; 23639540Ssklower { 237*50432Ssklower register struct isopcb *isop = sotoisopcb(so); 238*50432Ssklower register struct sockaddr_iso *siso; 23939540Ssklower int s, error = 0; 24039540Ssklower 24139540Ssklower if (req == PRU_CONTROL) 24239540Ssklower return (iso_control(so, (int)m, (caddr_t)nam, 24340771Ssklower (struct ifnet *)control)); 24441925Ssklower if ((isop == NULL && req != PRU_ATTACH) || 24541925Ssklower (control && control->m_len)) { 24639540Ssklower error = EINVAL; 24739540Ssklower goto release; 24839540Ssklower } 24939540Ssklower switch (req) { 25039540Ssklower 25139540Ssklower case PRU_ATTACH: 25239540Ssklower if (isop != NULL) { 25339540Ssklower error = EINVAL; 25439540Ssklower break; 25539540Ssklower } 25639540Ssklower error = iso_pcballoc(so, &cltb); 25739540Ssklower if (error) 25839540Ssklower break; 25939540Ssklower error = soreserve(so, cltp_sendspace, cltp_recvspace); 26039540Ssklower if (error) 26139540Ssklower break; 26239540Ssklower break; 26339540Ssklower 26439540Ssklower case PRU_DETACH: 26539540Ssklower iso_pcbdetach(isop); 26639540Ssklower break; 26739540Ssklower 26839540Ssklower case PRU_BIND: 26939540Ssklower error = iso_pcbbind(isop, nam); 27039540Ssklower break; 27139540Ssklower 27239540Ssklower case PRU_LISTEN: 27339540Ssklower error = EOPNOTSUPP; 27439540Ssklower break; 27539540Ssklower 27639540Ssklower case PRU_CONNECT: 27739540Ssklower if (isop->isop_faddr) { 27839540Ssklower error = EISCONN; 27939540Ssklower break; 28039540Ssklower } 28139540Ssklower error = iso_pcbconnect(isop, nam); 28239540Ssklower if (error == 0) 28339540Ssklower soisconnected(so); 28439540Ssklower break; 28539540Ssklower 28639540Ssklower case PRU_CONNECT2: 28739540Ssklower error = EOPNOTSUPP; 28839540Ssklower break; 28939540Ssklower 29039540Ssklower case PRU_ACCEPT: 29139540Ssklower error = EOPNOTSUPP; 29239540Ssklower break; 29339540Ssklower 29439540Ssklower case PRU_DISCONNECT: 29539540Ssklower if (isop->isop_faddr == 0) { 29639540Ssklower error = ENOTCONN; 29739540Ssklower break; 29839540Ssklower } 29939540Ssklower iso_pcbdisconnect(isop); 30039540Ssklower so->so_state &= ~SS_ISCONNECTED; /* XXX */ 30139540Ssklower break; 30239540Ssklower 30339540Ssklower case PRU_SHUTDOWN: 30439540Ssklower socantsendmore(so); 30539540Ssklower break; 30639540Ssklower 30739540Ssklower case PRU_SEND: 30839540Ssklower if (nam) { 30939540Ssklower if (isop->isop_faddr) { 31039540Ssklower error = EISCONN; 31139540Ssklower break; 31239540Ssklower } 31339540Ssklower /* 31439540Ssklower * Must block input while temporarily connected. 31539540Ssklower */ 31639540Ssklower s = splnet(); 31739540Ssklower error = iso_pcbconnect(isop, nam); 31839540Ssklower if (error) { 31939540Ssklower splx(s); 32039540Ssklower break; 32139540Ssklower } 32239540Ssklower } else { 32339540Ssklower if (isop->isop_faddr == 0) { 32439540Ssklower error = ENOTCONN; 32539540Ssklower break; 32639540Ssklower } 32739540Ssklower } 32839540Ssklower error = cltp_output(isop, m); 32939540Ssklower m = 0; 33039540Ssklower if (nam) { 33139540Ssklower iso_pcbdisconnect(isop); 33239540Ssklower splx(s); 33339540Ssklower } 33439540Ssklower break; 33539540Ssklower 33639540Ssklower case PRU_ABORT: 33739540Ssklower soisdisconnected(so); 33839540Ssklower iso_pcbdetach(isop); 33939540Ssklower break; 34039540Ssklower 34139540Ssklower case PRU_SOCKADDR: 342*50432Ssklower if (isop->isop_laddr) 343*50432Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), 344*50432Ssklower nam->m_len = isop->isop_laddr->siso_len); 34539540Ssklower break; 34639540Ssklower 34739540Ssklower case PRU_PEERADDR: 348*50432Ssklower if (isop->isop_faddr) 349*50432Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 350*50432Ssklower nam->m_len = isop->isop_faddr->siso_len); 35139540Ssklower break; 35239540Ssklower 35339540Ssklower case PRU_SENSE: 35439540Ssklower /* 35539540Ssklower * stat: don't bother with a blocksize. 35639540Ssklower */ 35739540Ssklower return (0); 35839540Ssklower 35939540Ssklower case PRU_SENDOOB: 36039540Ssklower case PRU_FASTTIMO: 36139540Ssklower case PRU_SLOWTIMO: 36239540Ssklower case PRU_PROTORCV: 36339540Ssklower case PRU_PROTOSEND: 36439540Ssklower error = EOPNOTSUPP; 36539540Ssklower break; 36639540Ssklower 36739540Ssklower case PRU_RCVD: 36839540Ssklower case PRU_RCVOOB: 36939540Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 37039540Ssklower 37139540Ssklower default: 37239540Ssklower panic("cltp_usrreq"); 37339540Ssklower } 37439540Ssklower release: 37541925Ssklower if (control != NULL) 37641925Ssklower m_freem(control); 37739540Ssklower if (m != NULL) 37839540Ssklower m_freem(m); 37939540Ssklower return (error); 38039540Ssklower } 381