139540Ssklower /*
2*63222Sbostic * Copyright (c) 1989, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
439540Ssklower *
544495Sbostic * %sccs.include.redist.c%
639540Ssklower *
7*63222Sbostic * @(#)cltp_usrreq.c 8.1 (Berkeley) 06/10/93
839540Ssklower */
939540Ssklower
1039540Ssklower #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */
1156533Sbostic #include <sys/param.h>
1256533Sbostic #include <sys/malloc.h>
1356533Sbostic #include <sys/mbuf.h>
1456533Sbostic #include <sys/protosw.h>
1556533Sbostic #include <sys/socket.h>
1656533Sbostic #include <sys/socketvar.h>
1756533Sbostic #include <sys/errno.h>
1856533Sbostic #include <sys/stat.h>
1939540Ssklower
2056533Sbostic #include <net/if.h>
2156533Sbostic #include <net/route.h>
2239540Ssklower
2356533Sbostic #include <netiso/argo_debug.h>
2456533Sbostic #include <netiso/iso.h>
2556533Sbostic #include <netiso/iso_pcb.h>
2656533Sbostic #include <netiso/iso_var.h>
2756533Sbostic #include <netiso/clnp.h>
2856533Sbostic #include <netiso/cltp_var.h>
2939540Ssklower #endif
3039540Ssklower
3139540Ssklower /*
3239540Ssklower * CLTP protocol implementation.
3339540Ssklower * Per ISO 8602, December, 1987.
3439540Ssklower */
cltp_init()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 */
cltp_notify(isop)13139540Ssklower cltp_notify(isop)
13239540Ssklower register struct isopcb *isop;
13339540Ssklower {
13439540Ssklower
13539540Ssklower sorwakeup(isop->isop_socket);
13639540Ssklower sowwakeup(isop->isop_socket);
13739540Ssklower }
13839540Ssklower
cltp_ctlinput(cmd,sa)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
cltp_output(isop,m)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 {
23750432Ssklower register struct isopcb *isop = sotoisopcb(so);
23839540Ssklower int s, error = 0;
23939540Ssklower
24039540Ssklower if (req == PRU_CONTROL)
24139540Ssklower return (iso_control(so, (int)m, (caddr_t)nam,
24240771Ssklower (struct ifnet *)control));
24341925Ssklower if ((isop == NULL && req != PRU_ATTACH) ||
24441925Ssklower (control && control->m_len)) {
24539540Ssklower error = EINVAL;
24639540Ssklower goto release;
24739540Ssklower }
24839540Ssklower switch (req) {
24939540Ssklower
25039540Ssklower case PRU_ATTACH:
25139540Ssklower if (isop != NULL) {
25239540Ssklower error = EINVAL;
25339540Ssklower break;
25439540Ssklower }
25539540Ssklower error = iso_pcballoc(so, &cltb);
25639540Ssklower if (error)
25739540Ssklower break;
25839540Ssklower error = soreserve(so, cltp_sendspace, cltp_recvspace);
25939540Ssklower if (error)
26039540Ssklower break;
26139540Ssklower break;
26239540Ssklower
26339540Ssklower case PRU_DETACH:
26439540Ssklower iso_pcbdetach(isop);
26539540Ssklower break;
26639540Ssklower
26739540Ssklower case PRU_BIND:
26839540Ssklower error = iso_pcbbind(isop, nam);
26939540Ssklower break;
27039540Ssklower
27139540Ssklower case PRU_LISTEN:
27239540Ssklower error = EOPNOTSUPP;
27339540Ssklower break;
27439540Ssklower
27539540Ssklower case PRU_CONNECT:
27639540Ssklower if (isop->isop_faddr) {
27739540Ssklower error = EISCONN;
27839540Ssklower break;
27939540Ssklower }
28039540Ssklower error = iso_pcbconnect(isop, nam);
28139540Ssklower if (error == 0)
28239540Ssklower soisconnected(so);
28339540Ssklower break;
28439540Ssklower
28539540Ssklower case PRU_CONNECT2:
28639540Ssklower error = EOPNOTSUPP;
28739540Ssklower break;
28839540Ssklower
28939540Ssklower case PRU_ACCEPT:
29039540Ssklower error = EOPNOTSUPP;
29139540Ssklower break;
29239540Ssklower
29339540Ssklower case PRU_DISCONNECT:
29439540Ssklower if (isop->isop_faddr == 0) {
29539540Ssklower error = ENOTCONN;
29639540Ssklower break;
29739540Ssklower }
29839540Ssklower iso_pcbdisconnect(isop);
29939540Ssklower so->so_state &= ~SS_ISCONNECTED; /* XXX */
30039540Ssklower break;
30139540Ssklower
30239540Ssklower case PRU_SHUTDOWN:
30339540Ssklower socantsendmore(so);
30439540Ssklower break;
30539540Ssklower
30639540Ssklower case PRU_SEND:
30739540Ssklower if (nam) {
30839540Ssklower if (isop->isop_faddr) {
30939540Ssklower error = EISCONN;
31039540Ssklower break;
31139540Ssklower }
31239540Ssklower /*
31339540Ssklower * Must block input while temporarily connected.
31439540Ssklower */
31539540Ssklower s = splnet();
31639540Ssklower error = iso_pcbconnect(isop, nam);
31739540Ssklower if (error) {
31839540Ssklower splx(s);
31939540Ssklower break;
32039540Ssklower }
32139540Ssklower } else {
32239540Ssklower if (isop->isop_faddr == 0) {
32339540Ssklower error = ENOTCONN;
32439540Ssklower break;
32539540Ssklower }
32639540Ssklower }
32739540Ssklower error = cltp_output(isop, m);
32839540Ssklower m = 0;
32939540Ssklower if (nam) {
33039540Ssklower iso_pcbdisconnect(isop);
33139540Ssklower splx(s);
33239540Ssklower }
33339540Ssklower break;
33439540Ssklower
33539540Ssklower case PRU_ABORT:
33639540Ssklower soisdisconnected(so);
33739540Ssklower iso_pcbdetach(isop);
33839540Ssklower break;
33939540Ssklower
34039540Ssklower case PRU_SOCKADDR:
34150432Ssklower if (isop->isop_laddr)
34250432Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t),
34350432Ssklower nam->m_len = isop->isop_laddr->siso_len);
34439540Ssklower break;
34539540Ssklower
34639540Ssklower case PRU_PEERADDR:
34750432Ssklower if (isop->isop_faddr)
34850432Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t),
34950432Ssklower nam->m_len = isop->isop_faddr->siso_len);
35039540Ssklower break;
35139540Ssklower
35239540Ssklower case PRU_SENSE:
35339540Ssklower /*
35439540Ssklower * stat: don't bother with a blocksize.
35539540Ssklower */
35639540Ssklower return (0);
35739540Ssklower
35839540Ssklower case PRU_SENDOOB:
35939540Ssklower case PRU_FASTTIMO:
36039540Ssklower case PRU_SLOWTIMO:
36139540Ssklower case PRU_PROTORCV:
36239540Ssklower case PRU_PROTOSEND:
36339540Ssklower error = EOPNOTSUPP;
36439540Ssklower break;
36539540Ssklower
36639540Ssklower case PRU_RCVD:
36739540Ssklower case PRU_RCVOOB:
36839540Ssklower return (EOPNOTSUPP); /* do not free mbuf's */
36939540Ssklower
37039540Ssklower default:
37139540Ssklower panic("cltp_usrreq");
37239540Ssklower }
37339540Ssklower release:
37441925Ssklower if (control != NULL)
37541925Ssklower m_freem(control);
37639540Ssklower if (m != NULL)
37739540Ssklower m_freem(m);
37839540Ssklower return (error);
37939540Ssklower }
380