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.6 (Berkeley) 06/27/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 #ifndef TP_LOCAL 227 /* XXXX should go in iso.h maybe? from tp_param.h, in any case */ 228 #define TP_LOCAL 22 229 #define TP_FOREIGN 33 230 #endif 231 232 u_long cltp_sendspace = 9216; /* really max datagram size */ 233 u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); 234 /* 40 1K datagrams */ 235 236 237 /*ARGSUSED*/ 238 cltp_usrreq(so, req, m, nam, control) 239 struct socket *so; 240 int req; 241 struct mbuf *m, *nam, *control; 242 { 243 struct isopcb *isop = sotoisopcb(so); 244 int s, error = 0; 245 246 if (req == PRU_CONTROL) 247 return (iso_control(so, (int)m, (caddr_t)nam, 248 (struct ifnet *)control)); 249 if ((isop == NULL && req != PRU_ATTACH) || 250 (control && control->m_len)) { 251 error = EINVAL; 252 goto release; 253 } 254 switch (req) { 255 256 case PRU_ATTACH: 257 if (isop != NULL) { 258 error = EINVAL; 259 break; 260 } 261 error = iso_pcballoc(so, &cltb); 262 if (error) 263 break; 264 error = soreserve(so, cltp_sendspace, cltp_recvspace); 265 if (error) 266 break; 267 break; 268 269 case PRU_DETACH: 270 iso_pcbdetach(isop); 271 break; 272 273 case PRU_BIND: 274 error = iso_pcbbind(isop, nam); 275 break; 276 277 case PRU_LISTEN: 278 error = EOPNOTSUPP; 279 break; 280 281 case PRU_CONNECT: 282 if (isop->isop_faddr) { 283 error = EISCONN; 284 break; 285 } 286 error = iso_pcbconnect(isop, nam); 287 if (error == 0) 288 soisconnected(so); 289 break; 290 291 case PRU_CONNECT2: 292 error = EOPNOTSUPP; 293 break; 294 295 case PRU_ACCEPT: 296 error = EOPNOTSUPP; 297 break; 298 299 case PRU_DISCONNECT: 300 if (isop->isop_faddr == 0) { 301 error = ENOTCONN; 302 break; 303 } 304 iso_pcbdisconnect(isop); 305 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 306 break; 307 308 case PRU_SHUTDOWN: 309 socantsendmore(so); 310 break; 311 312 case PRU_SEND: 313 if (nam) { 314 if (isop->isop_faddr) { 315 error = EISCONN; 316 break; 317 } 318 /* 319 * Must block input while temporarily connected. 320 */ 321 s = splnet(); 322 error = iso_pcbconnect(isop, nam); 323 if (error) { 324 splx(s); 325 break; 326 } 327 } else { 328 if (isop->isop_faddr == 0) { 329 error = ENOTCONN; 330 break; 331 } 332 } 333 error = cltp_output(isop, m); 334 m = 0; 335 if (nam) { 336 iso_pcbdisconnect(isop); 337 splx(s); 338 } 339 break; 340 341 case PRU_ABORT: 342 soisdisconnected(so); 343 iso_pcbdetach(isop); 344 break; 345 346 case PRU_SOCKADDR: 347 iso_getnetaddr(isop, nam, TP_LOCAL); 348 break; 349 350 case PRU_PEERADDR: 351 iso_getnetaddr(isop, nam, TP_FOREIGN); 352 break; 353 354 case PRU_SENSE: 355 /* 356 * stat: don't bother with a blocksize. 357 */ 358 return (0); 359 360 case PRU_SENDOOB: 361 case PRU_FASTTIMO: 362 case PRU_SLOWTIMO: 363 case PRU_PROTORCV: 364 case PRU_PROTOSEND: 365 error = EOPNOTSUPP; 366 break; 367 368 case PRU_RCVD: 369 case PRU_RCVOOB: 370 return (EOPNOTSUPP); /* do not free mbuf's */ 371 372 default: 373 panic("cltp_usrreq"); 374 } 375 release: 376 if (control != NULL) 377 m_freem(control); 378 if (m != NULL) 379 m_freem(m); 380 return (error); 381 } 382