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