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