1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)cltp_usrreq.c 8.1 (Berkeley) 06/10/93 8 */ 9 10 #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ 11 #include <sys/param.h> 12 #include <sys/malloc.h> 13 #include <sys/mbuf.h> 14 #include <sys/protosw.h> 15 #include <sys/socket.h> 16 #include <sys/socketvar.h> 17 #include <sys/errno.h> 18 #include <sys/stat.h> 19 20 #include <net/if.h> 21 #include <net/route.h> 22 23 #include <netiso/argo_debug.h> 24 #include <netiso/iso.h> 25 #include <netiso/iso_pcb.h> 26 #include <netiso/iso_var.h> 27 #include <netiso/clnp.h> 28 #include <netiso/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 int s, error = 0; 239 240 if (req == PRU_CONTROL) 241 return (iso_control(so, (int)m, (caddr_t)nam, 242 (struct ifnet *)control)); 243 if ((isop == NULL && req != PRU_ATTACH) || 244 (control && control->m_len)) { 245 error = EINVAL; 246 goto release; 247 } 248 switch (req) { 249 250 case PRU_ATTACH: 251 if (isop != NULL) { 252 error = EINVAL; 253 break; 254 } 255 error = iso_pcballoc(so, &cltb); 256 if (error) 257 break; 258 error = soreserve(so, cltp_sendspace, cltp_recvspace); 259 if (error) 260 break; 261 break; 262 263 case PRU_DETACH: 264 iso_pcbdetach(isop); 265 break; 266 267 case PRU_BIND: 268 error = iso_pcbbind(isop, nam); 269 break; 270 271 case PRU_LISTEN: 272 error = EOPNOTSUPP; 273 break; 274 275 case PRU_CONNECT: 276 if (isop->isop_faddr) { 277 error = EISCONN; 278 break; 279 } 280 error = iso_pcbconnect(isop, nam); 281 if (error == 0) 282 soisconnected(so); 283 break; 284 285 case PRU_CONNECT2: 286 error = EOPNOTSUPP; 287 break; 288 289 case PRU_ACCEPT: 290 error = EOPNOTSUPP; 291 break; 292 293 case PRU_DISCONNECT: 294 if (isop->isop_faddr == 0) { 295 error = ENOTCONN; 296 break; 297 } 298 iso_pcbdisconnect(isop); 299 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 300 break; 301 302 case PRU_SHUTDOWN: 303 socantsendmore(so); 304 break; 305 306 case PRU_SEND: 307 if (nam) { 308 if (isop->isop_faddr) { 309 error = EISCONN; 310 break; 311 } 312 /* 313 * Must block input while temporarily connected. 314 */ 315 s = splnet(); 316 error = iso_pcbconnect(isop, nam); 317 if (error) { 318 splx(s); 319 break; 320 } 321 } else { 322 if (isop->isop_faddr == 0) { 323 error = ENOTCONN; 324 break; 325 } 326 } 327 error = cltp_output(isop, m); 328 m = 0; 329 if (nam) { 330 iso_pcbdisconnect(isop); 331 splx(s); 332 } 333 break; 334 335 case PRU_ABORT: 336 soisdisconnected(so); 337 iso_pcbdetach(isop); 338 break; 339 340 case PRU_SOCKADDR: 341 if (isop->isop_laddr) 342 bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), 343 nam->m_len = isop->isop_laddr->siso_len); 344 break; 345 346 case PRU_PEERADDR: 347 if (isop->isop_faddr) 348 bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 349 nam->m_len = isop->isop_faddr->siso_len); 350 break; 351 352 case PRU_SENSE: 353 /* 354 * stat: don't bother with a blocksize. 355 */ 356 return (0); 357 358 case PRU_SENDOOB: 359 case PRU_FASTTIMO: 360 case PRU_SLOWTIMO: 361 case PRU_PROTORCV: 362 case PRU_PROTOSEND: 363 error = EOPNOTSUPP; 364 break; 365 366 case PRU_RCVD: 367 case PRU_RCVOOB: 368 return (EOPNOTSUPP); /* do not free mbuf's */ 369 370 default: 371 panic("cltp_usrreq"); 372 } 373 release: 374 if (control != NULL) 375 m_freem(control); 376 if (m != NULL) 377 m_freem(m); 378 return (error); 379 } 380