1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)cltp_usrreq.c 7.1 (Berkeley) 11/15/89 18 */ 19 20 #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ 21 #include "param.h" 22 #include "user.h" 23 #include "malloc.h" 24 #include "mbuf.h" 25 #include "protosw.h" 26 #include "socket.h" 27 #include "socketvar.h" 28 #include "errno.h" 29 #include "stat.h" 30 31 #include "../net/if.h" 32 #include "../net/route.h" 33 34 #include "argo_debug.h" 35 #include "iso.h" 36 #include "iso_pcb.h" 37 #include "iso_var.h" 38 #include "clnp.h" 39 #include "cltp_var.h" 40 #endif 41 42 /* 43 * CLTP protocol implementation. 44 * Per ISO 8602, December, 1987. 45 */ 46 cltp_init() 47 { 48 49 cltb.isop_next = cltb.isop_prev = &cltb; 50 } 51 52 int cltp_cksum = 1; 53 54 55 /* ARGUSED */ 56 cltp_input(m0, srcsa, dstsa, cons_channel, output) 57 struct mbuf *m0; 58 struct sockaddr *srcsa, *dstsa; 59 u_int cons_channel; 60 int (*output)(); 61 { 62 register struct isopcb *isop; 63 register struct mbuf *m = m0; 64 register u_char *up = mtod(m, u_char *); 65 register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa; 66 int len, hdrlen = *up + 1, dlen = 0; 67 u_char *uplim = up + hdrlen; 68 caddr_t dtsap; 69 70 for (len = 0; m; m = m->m_next) 71 len += m->m_len; 72 up += 2; /* skip header */ 73 while (up < uplim) switch (*up) { /* process options */ 74 case CLTPOVAL_SRC: 75 src->siso_tlen = up[1]; 76 src->siso_len = up[1] + TSEL(src) - (caddr_t)src; 77 if (src->siso_len < sizeof(*src)) 78 src->siso_len = sizeof(*src); 79 else if (src->siso_len > sizeof(*src)) { 80 MGET(m, M_DONTWAIT, MT_SONAME); 81 if (m == 0) 82 goto bad; 83 m->m_len = src->siso_len; 84 src = mtod(m, struct sockaddr_iso *); 85 bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len); 86 } 87 bcopy((caddr_t)up + 2, TSEL(src), up[1]); 88 up += 2 + src->siso_tlen; 89 continue; 90 91 case CLTPOVAL_DST: 92 dtsap = 2 + (caddr_t)up; 93 dlen = up[1]; 94 up += 2 + dlen; 95 continue; 96 97 case CLTPOVAL_CSM: 98 if (iso_check_csum(m0, len)) 99 goto bad; 100 up += 4; 101 102 default: 103 printf("clts: unknown option (%x)\n", up[0]); 104 goto bad; 105 } 106 if (dlen == 0 || src->siso_tlen == 0) 107 goto bad; 108 for (isop = cltb.isop_next;; isop = isop->isop_next) { 109 if (isop == &cltb) 110 goto bad; 111 if (isop->isop_laddr && 112 bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) 113 break; 114 } 115 m = m0; 116 m->m_len += hdrlen; 117 if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, 118 m, (struct mbuf *)0) == 0) 119 goto bad; 120 sorwakeup(isop->isop_socket); 121 m0 = 0; 122 bad: 123 if (src != (struct sockaddr_iso *)srcsa) 124 m_freem(dtom(src)); 125 if (m0) 126 m_freem(m0); 127 return; 128 } 129 130 /* 131 * Notify a cltp user of an asynchronous error; 132 * just wake up so that he can collect error status. 133 */ 134 cltp_notify(isop) 135 register struct isopcb *isop; 136 { 137 138 sorwakeup(isop->isop_socket); 139 sowwakeup(isop->isop_socket); 140 } 141 142 cltp_ctlinput(cmd, sa) 143 int cmd; 144 struct sockaddr *sa; 145 { 146 extern u_char inetctlerrmap[]; 147 struct sockaddr_iso *siso; 148 int iso_rtchange(); 149 150 if ((unsigned)cmd > PRC_NCMDS) 151 return; 152 if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) 153 return; 154 siso = (struct sockaddr_iso *)sa; 155 if (siso == 0 || siso->siso_nlen == 0) 156 return; 157 158 switch (cmd) { 159 case PRC_ROUTEDEAD: 160 case PRC_REDIRECT_NET: 161 case PRC_REDIRECT_HOST: 162 case PRC_REDIRECT_TOSNET: 163 case PRC_REDIRECT_TOSHOST: 164 iso_pcbnotify(&cltb, siso, 165 (int)inetctlerrmap[cmd], iso_rtchange); 166 break; 167 168 default: 169 if (inetctlerrmap[cmd] == 0) 170 return; /* XXX */ 171 iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], 172 cltp_notify); 173 } 174 } 175 176 cltp_output(isop, m) 177 register struct isopcb *isop; 178 register struct mbuf *m; 179 { 180 register int len; 181 register struct sockaddr_iso *siso; 182 int hdrlen, error = 0, docsum; 183 register u_char *up; 184 185 if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { 186 error = ENOTCONN; 187 goto bad; 188 } 189 /* 190 * Calculate data length and get a mbuf for CLTP header. 191 */ 192 hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen 193 + 2 + isop->isop_faddr->siso_tlen; 194 if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) 195 hdrlen += 4; 196 M_PREPEND(m, hdrlen, M_WAIT); 197 len = m->m_pkthdr.len; 198 /* 199 * Fill in mbuf with extended CLTP header 200 */ 201 up = mtod(m, u_char *); 202 up[0] = UD_TPDU_type; 203 up[1] = hdrlen - 1; 204 up[2] = CLTPOVAL_DST; 205 up[3] = (siso = isop->isop_laddr)->siso_tlen; 206 up += 4; 207 bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 208 up += siso->siso_tlen; 209 up[0] = CLTPOVAL_SRC; 210 up[1] = (siso = isop->isop_faddr)->siso_tlen; 211 up += 2; 212 bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 213 /* 214 * Stuff checksum and output datagram. 215 */ 216 if (docsum) { 217 up += siso->siso_tlen; 218 up[0] = CLTPOVAL_CSM; 219 up[1] = 2; 220 iso_gen_cksum(m, 2 + up - mtod(m, u_char *), len); 221 } 222 return (tpclnp_output(isop, m, len, !docsum)); 223 bad: 224 m_freem(m); 225 return (error); 226 } 227 228 #ifndef TP_LOCAL 229 /* XXXX should go in iso.h maybe? from tp_param.h, in any case */ 230 #define TP_LOCAL 22 231 #define TP_FOREIGN 33 232 #endif 233 234 u_long cltp_sendspace = 9216; /* really max datagram size */ 235 u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); 236 /* 40 1K datagrams */ 237 238 239 /*ARGSUSED*/ 240 cltp_usrreq(so, req, m, nam, rights, control) 241 struct socket *so; 242 int req; 243 struct mbuf *m, *nam, *rights, *control; 244 { 245 struct isopcb *isop = sotoisopcb(so); 246 int s, error = 0; 247 248 if (req == PRU_CONTROL) 249 return (iso_control(so, (int)m, (caddr_t)nam, 250 (struct ifnet *)rights)); 251 if (rights && rights->m_len) { 252 error = EINVAL; 253 goto release; 254 } 255 if (isop == NULL && req != PRU_ATTACH) { 256 error = EINVAL; 257 goto release; 258 } 259 switch (req) { 260 261 case PRU_ATTACH: 262 if (isop != NULL) { 263 error = EINVAL; 264 break; 265 } 266 error = iso_pcballoc(so, &cltb); 267 if (error) 268 break; 269 error = soreserve(so, cltp_sendspace, cltp_recvspace); 270 if (error) 271 break; 272 break; 273 274 case PRU_DETACH: 275 iso_pcbdetach(isop); 276 break; 277 278 case PRU_BIND: 279 error = iso_pcbbind(isop, nam); 280 break; 281 282 case PRU_LISTEN: 283 error = EOPNOTSUPP; 284 break; 285 286 case PRU_CONNECT: 287 if (isop->isop_faddr) { 288 error = EISCONN; 289 break; 290 } 291 error = iso_pcbconnect(isop, nam); 292 if (error == 0) 293 soisconnected(so); 294 break; 295 296 case PRU_CONNECT2: 297 error = EOPNOTSUPP; 298 break; 299 300 case PRU_ACCEPT: 301 error = EOPNOTSUPP; 302 break; 303 304 case PRU_DISCONNECT: 305 if (isop->isop_faddr == 0) { 306 error = ENOTCONN; 307 break; 308 } 309 iso_pcbdisconnect(isop); 310 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 311 break; 312 313 case PRU_SHUTDOWN: 314 socantsendmore(so); 315 break; 316 317 case PRU_SEND: 318 if (nam) { 319 if (isop->isop_faddr) { 320 error = EISCONN; 321 break; 322 } 323 /* 324 * Must block input while temporarily connected. 325 */ 326 s = splnet(); 327 error = iso_pcbconnect(isop, nam); 328 if (error) { 329 splx(s); 330 break; 331 } 332 } else { 333 if (isop->isop_faddr == 0) { 334 error = ENOTCONN; 335 break; 336 } 337 } 338 error = cltp_output(isop, m); 339 m = 0; 340 if (nam) { 341 iso_pcbdisconnect(isop); 342 splx(s); 343 } 344 break; 345 346 case PRU_ABORT: 347 soisdisconnected(so); 348 iso_pcbdetach(isop); 349 break; 350 351 case PRU_SOCKADDR: 352 iso_getnetaddr(isop, nam, TP_LOCAL); 353 break; 354 355 case PRU_PEERADDR: 356 iso_getnetaddr(isop, nam, TP_FOREIGN); 357 break; 358 359 case PRU_SENSE: 360 /* 361 * stat: don't bother with a blocksize. 362 */ 363 return (0); 364 365 case PRU_SENDOOB: 366 case PRU_FASTTIMO: 367 case PRU_SLOWTIMO: 368 case PRU_PROTORCV: 369 case PRU_PROTOSEND: 370 error = EOPNOTSUPP; 371 break; 372 373 case PRU_RCVD: 374 case PRU_RCVOOB: 375 return (EOPNOTSUPP); /* do not free mbuf's */ 376 377 default: 378 panic("cltp_usrreq"); 379 } 380 release: 381 if (m != NULL) 382 m_freem(m); 383 return (error); 384 } 385