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.4 (Berkeley) 05/14/90 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 cltpstat.cltps_badsum++; 100 goto bad; 101 } 102 up += 4; 103 continue; 104 105 default: 106 printf("clts: unknown option (%x)\n", up[0]); 107 cltpstat.cltps_hdrops++; 108 goto bad; 109 } 110 if (dlen == 0 || src->siso_tlen == 0) 111 goto bad; 112 for (isop = cltb.isop_next;; isop = isop->isop_next) { 113 if (isop == &cltb) { 114 cltpstat.cltps_noport++; 115 goto bad; 116 } 117 if (isop->isop_laddr && 118 bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) 119 break; 120 } 121 m = m0; 122 m->m_len -= hdrlen; 123 m->m_data += hdrlen; 124 if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, 125 m, (struct mbuf *)0) == 0) 126 goto bad; 127 cltpstat.cltps_ipackets++; 128 sorwakeup(isop->isop_socket); 129 m0 = 0; 130 bad: 131 if (src != (struct sockaddr_iso *)srcsa) 132 m_freem(dtom(src)); 133 if (m0) 134 m_freem(m0); 135 return 0; 136 } 137 138 /* 139 * Notify a cltp user of an asynchronous error; 140 * just wake up so that he can collect error status. 141 */ 142 cltp_notify(isop) 143 register struct isopcb *isop; 144 { 145 146 sorwakeup(isop->isop_socket); 147 sowwakeup(isop->isop_socket); 148 } 149 150 cltp_ctlinput(cmd, sa) 151 int cmd; 152 struct sockaddr *sa; 153 { 154 extern u_char inetctlerrmap[]; 155 struct sockaddr_iso *siso; 156 int iso_rtchange(); 157 158 if ((unsigned)cmd > PRC_NCMDS) 159 return; 160 if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) 161 return; 162 siso = (struct sockaddr_iso *)sa; 163 if (siso == 0 || siso->siso_nlen == 0) 164 return; 165 166 switch (cmd) { 167 case PRC_ROUTEDEAD: 168 case PRC_REDIRECT_NET: 169 case PRC_REDIRECT_HOST: 170 case PRC_REDIRECT_TOSNET: 171 case PRC_REDIRECT_TOSHOST: 172 iso_pcbnotify(&cltb, siso, 173 (int)inetctlerrmap[cmd], iso_rtchange); 174 break; 175 176 default: 177 if (inetctlerrmap[cmd] == 0) 178 return; /* XXX */ 179 iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], 180 cltp_notify); 181 } 182 } 183 184 cltp_output(isop, m) 185 register struct isopcb *isop; 186 register struct mbuf *m; 187 { 188 register int len; 189 register struct sockaddr_iso *siso; 190 int hdrlen, error = 0, docsum; 191 register u_char *up; 192 193 if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { 194 error = ENOTCONN; 195 goto bad; 196 } 197 /* 198 * Calculate data length and get a mbuf for CLTP header. 199 */ 200 hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen 201 + 2 + isop->isop_faddr->siso_tlen; 202 if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) 203 hdrlen += 4; 204 M_PREPEND(m, hdrlen, M_WAIT); 205 len = m->m_pkthdr.len; 206 /* 207 * Fill in mbuf with extended CLTP header 208 */ 209 up = mtod(m, u_char *); 210 up[0] = hdrlen - 1; 211 up[1] = UD_TPDU_type; 212 up[2] = CLTPOVAL_SRC; 213 up[3] = (siso = isop->isop_laddr)->siso_tlen; 214 up += 4; 215 bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 216 up += siso->siso_tlen; 217 up[0] = CLTPOVAL_DST; 218 up[1] = (siso = isop->isop_faddr)->siso_tlen; 219 up += 2; 220 bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); 221 /* 222 * Stuff checksum and output datagram. 223 */ 224 if (docsum) { 225 up += siso->siso_tlen; 226 up[0] = CLTPOVAL_CSM; 227 up[1] = 2; 228 iso_gen_csum(m, 2 + up - mtod(m, u_char *), len); 229 } 230 cltpstat.cltps_opackets++; 231 return (tpclnp_output(isop, m, len, !docsum)); 232 bad: 233 m_freem(m); 234 return (error); 235 } 236 237 #ifndef TP_LOCAL 238 /* XXXX should go in iso.h maybe? from tp_param.h, in any case */ 239 #define TP_LOCAL 22 240 #define TP_FOREIGN 33 241 #endif 242 243 u_long cltp_sendspace = 9216; /* really max datagram size */ 244 u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); 245 /* 40 1K datagrams */ 246 247 248 /*ARGSUSED*/ 249 cltp_usrreq(so, req, m, nam, control) 250 struct socket *so; 251 int req; 252 struct mbuf *m, *nam, *control; 253 { 254 struct isopcb *isop = sotoisopcb(so); 255 int s, error = 0; 256 257 if (req == PRU_CONTROL) 258 return (iso_control(so, (int)m, (caddr_t)nam, 259 (struct ifnet *)control)); 260 if ((isop == NULL && req != PRU_ATTACH) || 261 (control && control->m_len)) { 262 error = EINVAL; 263 goto release; 264 } 265 switch (req) { 266 267 case PRU_ATTACH: 268 if (isop != NULL) { 269 error = EINVAL; 270 break; 271 } 272 error = iso_pcballoc(so, &cltb); 273 if (error) 274 break; 275 error = soreserve(so, cltp_sendspace, cltp_recvspace); 276 if (error) 277 break; 278 break; 279 280 case PRU_DETACH: 281 iso_pcbdetach(isop); 282 break; 283 284 case PRU_BIND: 285 error = iso_pcbbind(isop, nam); 286 break; 287 288 case PRU_LISTEN: 289 error = EOPNOTSUPP; 290 break; 291 292 case PRU_CONNECT: 293 if (isop->isop_faddr) { 294 error = EISCONN; 295 break; 296 } 297 error = iso_pcbconnect(isop, nam); 298 if (error == 0) 299 soisconnected(so); 300 break; 301 302 case PRU_CONNECT2: 303 error = EOPNOTSUPP; 304 break; 305 306 case PRU_ACCEPT: 307 error = EOPNOTSUPP; 308 break; 309 310 case PRU_DISCONNECT: 311 if (isop->isop_faddr == 0) { 312 error = ENOTCONN; 313 break; 314 } 315 iso_pcbdisconnect(isop); 316 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 317 break; 318 319 case PRU_SHUTDOWN: 320 socantsendmore(so); 321 break; 322 323 case PRU_SEND: 324 if (nam) { 325 if (isop->isop_faddr) { 326 error = EISCONN; 327 break; 328 } 329 /* 330 * Must block input while temporarily connected. 331 */ 332 s = splnet(); 333 error = iso_pcbconnect(isop, nam); 334 if (error) { 335 splx(s); 336 break; 337 } 338 } else { 339 if (isop->isop_faddr == 0) { 340 error = ENOTCONN; 341 break; 342 } 343 } 344 error = cltp_output(isop, m); 345 m = 0; 346 if (nam) { 347 iso_pcbdisconnect(isop); 348 splx(s); 349 } 350 break; 351 352 case PRU_ABORT: 353 soisdisconnected(so); 354 iso_pcbdetach(isop); 355 break; 356 357 case PRU_SOCKADDR: 358 iso_getnetaddr(isop, nam, TP_LOCAL); 359 break; 360 361 case PRU_PEERADDR: 362 iso_getnetaddr(isop, nam, TP_FOREIGN); 363 break; 364 365 case PRU_SENSE: 366 /* 367 * stat: don't bother with a blocksize. 368 */ 369 return (0); 370 371 case PRU_SENDOOB: 372 case PRU_FASTTIMO: 373 case PRU_SLOWTIMO: 374 case PRU_PROTORCV: 375 case PRU_PROTOSEND: 376 error = EOPNOTSUPP; 377 break; 378 379 case PRU_RCVD: 380 case PRU_RCVOOB: 381 return (EOPNOTSUPP); /* do not free mbuf's */ 382 383 default: 384 panic("cltp_usrreq"); 385 } 386 release: 387 if (control != NULL) 388 m_freem(control); 389 if (m != NULL) 390 m_freem(m); 391 return (error); 392 } 393