139540Ssklower /* 239540Ssklower * Copyright (c) 1989 Regents of the University of California. 339540Ssklower * All rights reserved. 439540Ssklower * 539540Ssklower * Redistribution and use in source and binary forms are permitted 639540Ssklower * provided that the above copyright notice and this paragraph are 739540Ssklower * duplicated in all such forms and that any documentation, 839540Ssklower * advertising materials, and other materials related to such 939540Ssklower * distribution and use acknowledge that the software was developed 1039540Ssklower * by the University of California, Berkeley. The name of the 1139540Ssklower * University may not be used to endorse or promote products derived 1239540Ssklower * from this software without specific prior written permission. 1339540Ssklower * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439540Ssklower * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539540Ssklower * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639540Ssklower * 17*39925Ssklower * @(#)cltp_usrreq.c 7.2 (Berkeley) 01/16/90 1839540Ssklower */ 1939540Ssklower 2039540Ssklower #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ 2139540Ssklower #include "param.h" 2239540Ssklower #include "user.h" 2339540Ssklower #include "malloc.h" 2439540Ssklower #include "mbuf.h" 2539540Ssklower #include "protosw.h" 2639540Ssklower #include "socket.h" 2739540Ssklower #include "socketvar.h" 2839540Ssklower #include "errno.h" 2939540Ssklower #include "stat.h" 3039540Ssklower 3139540Ssklower #include "../net/if.h" 3239540Ssklower #include "../net/route.h" 3339540Ssklower 3439540Ssklower #include "argo_debug.h" 3539540Ssklower #include "iso.h" 3639540Ssklower #include "iso_pcb.h" 3739540Ssklower #include "iso_var.h" 3839540Ssklower #include "clnp.h" 3939540Ssklower #include "cltp_var.h" 4039540Ssklower #endif 4139540Ssklower 4239540Ssklower /* 4339540Ssklower * CLTP protocol implementation. 4439540Ssklower * Per ISO 8602, December, 1987. 4539540Ssklower */ 4639540Ssklower cltp_init() 4739540Ssklower { 4839540Ssklower 4939540Ssklower cltb.isop_next = cltb.isop_prev = &cltb; 5039540Ssklower } 5139540Ssklower 5239540Ssklower int cltp_cksum = 1; 5339540Ssklower 5439540Ssklower 5539540Ssklower /* ARGUSED */ 5639540Ssklower cltp_input(m0, srcsa, dstsa, cons_channel, output) 5739540Ssklower struct mbuf *m0; 5839540Ssklower struct sockaddr *srcsa, *dstsa; 5939540Ssklower u_int cons_channel; 6039540Ssklower int (*output)(); 6139540Ssklower { 6239540Ssklower register struct isopcb *isop; 6339540Ssklower register struct mbuf *m = m0; 6439540Ssklower register u_char *up = mtod(m, u_char *); 6539540Ssklower register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa; 6639540Ssklower int len, hdrlen = *up + 1, dlen = 0; 6739540Ssklower u_char *uplim = up + hdrlen; 6839540Ssklower caddr_t dtsap; 6939540Ssklower 7039540Ssklower for (len = 0; m; m = m->m_next) 7139540Ssklower len += m->m_len; 7239540Ssklower up += 2; /* skip header */ 7339540Ssklower while (up < uplim) switch (*up) { /* process options */ 7439540Ssklower case CLTPOVAL_SRC: 7539540Ssklower src->siso_tlen = up[1]; 7639540Ssklower src->siso_len = up[1] + TSEL(src) - (caddr_t)src; 7739540Ssklower if (src->siso_len < sizeof(*src)) 7839540Ssklower src->siso_len = sizeof(*src); 7939540Ssklower else if (src->siso_len > sizeof(*src)) { 8039540Ssklower MGET(m, M_DONTWAIT, MT_SONAME); 8139540Ssklower if (m == 0) 8239540Ssklower goto bad; 8339540Ssklower m->m_len = src->siso_len; 8439540Ssklower src = mtod(m, struct sockaddr_iso *); 8539540Ssklower bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len); 8639540Ssklower } 8739540Ssklower bcopy((caddr_t)up + 2, TSEL(src), up[1]); 8839540Ssklower up += 2 + src->siso_tlen; 8939540Ssklower continue; 9039540Ssklower 9139540Ssklower case CLTPOVAL_DST: 9239540Ssklower dtsap = 2 + (caddr_t)up; 9339540Ssklower dlen = up[1]; 9439540Ssklower up += 2 + dlen; 9539540Ssklower continue; 9639540Ssklower 9739540Ssklower case CLTPOVAL_CSM: 98*39925Ssklower if (iso_check_csum(m0, len)) { 99*39925Ssklower cltpstat.cltps_badsum++; 10039540Ssklower goto bad; 101*39925Ssklower } 10239540Ssklower up += 4; 103*39925Ssklower continue; 10439540Ssklower 10539540Ssklower default: 10639540Ssklower printf("clts: unknown option (%x)\n", up[0]); 107*39925Ssklower cltpstat.cltps_hdrops++; 10839540Ssklower goto bad; 10939540Ssklower } 11039540Ssklower if (dlen == 0 || src->siso_tlen == 0) 11139540Ssklower goto bad; 11239540Ssklower for (isop = cltb.isop_next;; isop = isop->isop_next) { 113*39925Ssklower if (isop == &cltb) { 114*39925Ssklower cltpstat.cltps_noport++; 11539540Ssklower goto bad; 116*39925Ssklower } 11739540Ssklower if (isop->isop_laddr && 11839540Ssklower bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) 11939540Ssklower break; 12039540Ssklower } 12139540Ssklower m = m0; 122*39925Ssklower m->m_len -= hdrlen; 123*39925Ssklower m->m_data += hdrlen; 12439540Ssklower if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, 12539540Ssklower m, (struct mbuf *)0) == 0) 12639540Ssklower goto bad; 127*39925Ssklower cltpstat.cltps_ipackets++; 12839540Ssklower sorwakeup(isop->isop_socket); 12939540Ssklower m0 = 0; 13039540Ssklower bad: 13139540Ssklower if (src != (struct sockaddr_iso *)srcsa) 13239540Ssklower m_freem(dtom(src)); 13339540Ssklower if (m0) 13439540Ssklower m_freem(m0); 135*39925Ssklower return 0; 13639540Ssklower } 13739540Ssklower 13839540Ssklower /* 13939540Ssklower * Notify a cltp user of an asynchronous error; 14039540Ssklower * just wake up so that he can collect error status. 14139540Ssklower */ 14239540Ssklower cltp_notify(isop) 14339540Ssklower register struct isopcb *isop; 14439540Ssklower { 14539540Ssklower 14639540Ssklower sorwakeup(isop->isop_socket); 14739540Ssklower sowwakeup(isop->isop_socket); 14839540Ssklower } 14939540Ssklower 15039540Ssklower cltp_ctlinput(cmd, sa) 15139540Ssklower int cmd; 15239540Ssklower struct sockaddr *sa; 15339540Ssklower { 15439540Ssklower extern u_char inetctlerrmap[]; 15539540Ssklower struct sockaddr_iso *siso; 15639540Ssklower int iso_rtchange(); 15739540Ssklower 15839540Ssklower if ((unsigned)cmd > PRC_NCMDS) 15939540Ssklower return; 16039540Ssklower if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) 16139540Ssklower return; 16239540Ssklower siso = (struct sockaddr_iso *)sa; 16339540Ssklower if (siso == 0 || siso->siso_nlen == 0) 16439540Ssklower return; 16539540Ssklower 16639540Ssklower switch (cmd) { 16739540Ssklower case PRC_ROUTEDEAD: 16839540Ssklower case PRC_REDIRECT_NET: 16939540Ssklower case PRC_REDIRECT_HOST: 17039540Ssklower case PRC_REDIRECT_TOSNET: 17139540Ssklower case PRC_REDIRECT_TOSHOST: 17239540Ssklower iso_pcbnotify(&cltb, siso, 17339540Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 17439540Ssklower break; 17539540Ssklower 17639540Ssklower default: 17739540Ssklower if (inetctlerrmap[cmd] == 0) 17839540Ssklower return; /* XXX */ 17939540Ssklower iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], 18039540Ssklower cltp_notify); 18139540Ssklower } 18239540Ssklower } 18339540Ssklower 18439540Ssklower cltp_output(isop, m) 18539540Ssklower register struct isopcb *isop; 18639540Ssklower register struct mbuf *m; 18739540Ssklower { 18839540Ssklower register int len; 18939540Ssklower register struct sockaddr_iso *siso; 19039540Ssklower int hdrlen, error = 0, docsum; 19139540Ssklower register u_char *up; 19239540Ssklower 19339540Ssklower if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { 19439540Ssklower error = ENOTCONN; 19539540Ssklower goto bad; 19639540Ssklower } 19739540Ssklower /* 19839540Ssklower * Calculate data length and get a mbuf for CLTP header. 19939540Ssklower */ 20039540Ssklower hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen 20139540Ssklower + 2 + isop->isop_faddr->siso_tlen; 20239540Ssklower if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) 20339540Ssklower hdrlen += 4; 20439540Ssklower M_PREPEND(m, hdrlen, M_WAIT); 20539540Ssklower len = m->m_pkthdr.len; 20639540Ssklower /* 20739540Ssklower * Fill in mbuf with extended CLTP header 20839540Ssklower */ 20939540Ssklower up = mtod(m, u_char *); 210*39925Ssklower up[0] = hdrlen - 1; 211*39925Ssklower up[1] = UD_TPDU_type; 212*39925Ssklower up[2] = CLTPOVAL_SRC; 21339540Ssklower up[3] = (siso = isop->isop_laddr)->siso_tlen; 21439540Ssklower up += 4; 21539540Ssklower bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 21639540Ssklower up += siso->siso_tlen; 217*39925Ssklower up[0] = CLTPOVAL_DST; 21839540Ssklower up[1] = (siso = isop->isop_faddr)->siso_tlen; 21939540Ssklower up += 2; 22039540Ssklower bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 22139540Ssklower /* 22239540Ssklower * Stuff checksum and output datagram. 22339540Ssklower */ 22439540Ssklower if (docsum) { 22539540Ssklower up += siso->siso_tlen; 22639540Ssklower up[0] = CLTPOVAL_CSM; 22739540Ssklower up[1] = 2; 228*39925Ssklower iso_gen_csum(m, 2 + up - mtod(m, u_char *), len); 22939540Ssklower } 230*39925Ssklower cltpstat.cltps_opackets++; 23139540Ssklower return (tpclnp_output(isop, m, len, !docsum)); 23239540Ssklower bad: 23339540Ssklower m_freem(m); 23439540Ssklower return (error); 23539540Ssklower } 23639540Ssklower 23739540Ssklower #ifndef TP_LOCAL 23839540Ssklower /* XXXX should go in iso.h maybe? from tp_param.h, in any case */ 23939540Ssklower #define TP_LOCAL 22 24039540Ssklower #define TP_FOREIGN 33 24139540Ssklower #endif 24239540Ssklower 24339540Ssklower u_long cltp_sendspace = 9216; /* really max datagram size */ 24439540Ssklower u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); 24539540Ssklower /* 40 1K datagrams */ 24639540Ssklower 24739540Ssklower 24839540Ssklower /*ARGSUSED*/ 24939540Ssklower cltp_usrreq(so, req, m, nam, rights, control) 25039540Ssklower struct socket *so; 25139540Ssklower int req; 25239540Ssklower struct mbuf *m, *nam, *rights, *control; 25339540Ssklower { 25439540Ssklower struct isopcb *isop = sotoisopcb(so); 25539540Ssklower int s, error = 0; 25639540Ssklower 25739540Ssklower if (req == PRU_CONTROL) 25839540Ssklower return (iso_control(so, (int)m, (caddr_t)nam, 25939540Ssklower (struct ifnet *)rights)); 26039540Ssklower if (rights && rights->m_len) { 26139540Ssklower error = EINVAL; 26239540Ssklower goto release; 26339540Ssklower } 26439540Ssklower if (isop == NULL && req != PRU_ATTACH) { 26539540Ssklower error = EINVAL; 26639540Ssklower goto release; 26739540Ssklower } 26839540Ssklower switch (req) { 26939540Ssklower 27039540Ssklower case PRU_ATTACH: 27139540Ssklower if (isop != NULL) { 27239540Ssklower error = EINVAL; 27339540Ssklower break; 27439540Ssklower } 27539540Ssklower error = iso_pcballoc(so, &cltb); 27639540Ssklower if (error) 27739540Ssklower break; 27839540Ssklower error = soreserve(so, cltp_sendspace, cltp_recvspace); 27939540Ssklower if (error) 28039540Ssklower break; 28139540Ssklower break; 28239540Ssklower 28339540Ssklower case PRU_DETACH: 28439540Ssklower iso_pcbdetach(isop); 28539540Ssklower break; 28639540Ssklower 28739540Ssklower case PRU_BIND: 28839540Ssklower error = iso_pcbbind(isop, nam); 28939540Ssklower break; 29039540Ssklower 29139540Ssklower case PRU_LISTEN: 29239540Ssklower error = EOPNOTSUPP; 29339540Ssklower break; 29439540Ssklower 29539540Ssklower case PRU_CONNECT: 29639540Ssklower if (isop->isop_faddr) { 29739540Ssklower error = EISCONN; 29839540Ssklower break; 29939540Ssklower } 30039540Ssklower error = iso_pcbconnect(isop, nam); 30139540Ssklower if (error == 0) 30239540Ssklower soisconnected(so); 30339540Ssklower break; 30439540Ssklower 30539540Ssklower case PRU_CONNECT2: 30639540Ssklower error = EOPNOTSUPP; 30739540Ssklower break; 30839540Ssklower 30939540Ssklower case PRU_ACCEPT: 31039540Ssklower error = EOPNOTSUPP; 31139540Ssklower break; 31239540Ssklower 31339540Ssklower case PRU_DISCONNECT: 31439540Ssklower if (isop->isop_faddr == 0) { 31539540Ssklower error = ENOTCONN; 31639540Ssklower break; 31739540Ssklower } 31839540Ssklower iso_pcbdisconnect(isop); 31939540Ssklower so->so_state &= ~SS_ISCONNECTED; /* XXX */ 32039540Ssklower break; 32139540Ssklower 32239540Ssklower case PRU_SHUTDOWN: 32339540Ssklower socantsendmore(so); 32439540Ssklower break; 32539540Ssklower 32639540Ssklower case PRU_SEND: 32739540Ssklower if (nam) { 32839540Ssklower if (isop->isop_faddr) { 32939540Ssklower error = EISCONN; 33039540Ssklower break; 33139540Ssklower } 33239540Ssklower /* 33339540Ssklower * Must block input while temporarily connected. 33439540Ssklower */ 33539540Ssklower s = splnet(); 33639540Ssklower error = iso_pcbconnect(isop, nam); 33739540Ssklower if (error) { 33839540Ssklower splx(s); 33939540Ssklower break; 34039540Ssklower } 34139540Ssklower } else { 34239540Ssklower if (isop->isop_faddr == 0) { 34339540Ssklower error = ENOTCONN; 34439540Ssklower break; 34539540Ssklower } 34639540Ssklower } 34739540Ssklower error = cltp_output(isop, m); 34839540Ssklower m = 0; 34939540Ssklower if (nam) { 35039540Ssklower iso_pcbdisconnect(isop); 35139540Ssklower splx(s); 35239540Ssklower } 35339540Ssklower break; 35439540Ssklower 35539540Ssklower case PRU_ABORT: 35639540Ssklower soisdisconnected(so); 35739540Ssklower iso_pcbdetach(isop); 35839540Ssklower break; 35939540Ssklower 36039540Ssklower case PRU_SOCKADDR: 36139540Ssklower iso_getnetaddr(isop, nam, TP_LOCAL); 36239540Ssklower break; 36339540Ssklower 36439540Ssklower case PRU_PEERADDR: 36539540Ssklower iso_getnetaddr(isop, nam, TP_FOREIGN); 36639540Ssklower break; 36739540Ssklower 36839540Ssklower case PRU_SENSE: 36939540Ssklower /* 37039540Ssklower * stat: don't bother with a blocksize. 37139540Ssklower */ 37239540Ssklower return (0); 37339540Ssklower 37439540Ssklower case PRU_SENDOOB: 37539540Ssklower case PRU_FASTTIMO: 37639540Ssklower case PRU_SLOWTIMO: 37739540Ssklower case PRU_PROTORCV: 37839540Ssklower case PRU_PROTOSEND: 37939540Ssklower error = EOPNOTSUPP; 38039540Ssklower break; 38139540Ssklower 38239540Ssklower case PRU_RCVD: 38339540Ssklower case PRU_RCVOOB: 38439540Ssklower return (EOPNOTSUPP); /* do not free mbuf's */ 38539540Ssklower 38639540Ssklower default: 38739540Ssklower panic("cltp_usrreq"); 38839540Ssklower } 38939540Ssklower release: 39039540Ssklower if (m != NULL) 39139540Ssklower m_freem(m); 39239540Ssklower return (error); 39339540Ssklower } 394