1 /* 2 * Copyright (c) University of British Columbia, 1984 3 * Copyright (C) Computer Science Department IV, 4 * University of Erlangen-Nuremberg, Germany, 1992 5 * Copyright (c) 1991, 1992 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by the 9 * Laboratory for Computation Vision and the Computer Science Department 10 * of the the University of British Columbia and the Computer Science 11 * Department (IV) of the University of Erlangen-Nuremberg, Germany. 12 * 13 * %sccs.include.redist.c% 14 * 15 * @(#)pk_usrreq.c 7.18 (Berkeley) 12/08/92 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/mbuf.h> 21 #include <sys/socket.h> 22 #include <sys/socketvar.h> 23 #include <sys/protosw.h> 24 #include <sys/errno.h> 25 #include <sys/ioctl.h> 26 #include <sys/stat.h> 27 28 #include <net/if.h> 29 #include <net/route.h> 30 31 #include <netccitt/x25.h> 32 #include <netccitt/pk.h> 33 #include <netccitt/pk_var.h> 34 35 static old_to_new(); 36 static new_to_old(); 37 /* 38 * 39 * X.25 Packet level protocol interface to socket abstraction. 40 * 41 * Process an X.25 user request on a logical channel. If this is a send 42 * request then m is the mbuf chain of the send data. If this is a timer 43 * expiration (called from the software clock routine) them timertype is 44 * the particular timer. 45 * 46 */ 47 48 pk_usrreq (so, req, m, nam, control) 49 struct socket *so; 50 int req; 51 register struct mbuf *m, *nam; 52 struct mbuf *control; 53 { 54 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 55 register int error = 0; 56 57 if (req == PRU_CONTROL) 58 return (pk_control (so, (int)m, (caddr_t)nam, 59 (struct ifnet *)control)); 60 if (control && control -> m_len) { 61 error = EINVAL; 62 goto release; 63 } 64 if (lcp == NULL && req != PRU_ATTACH) { 65 error = EINVAL; 66 goto release; 67 } 68 69 /* 70 pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, 71 req, (struct x25_packet *)0); 72 */ 73 74 switch (req) { 75 /* 76 * X.25 attaches to socket via PRU_ATTACH and allocates a logical 77 * channel descriptor. If the socket is to receive connections, 78 * then the LISTEN state is entered. 79 */ 80 case PRU_ATTACH: 81 if (lcp) { 82 error = EISCONN; 83 /* Socket already connected. */ 84 break; 85 } 86 lcp = pk_attach (so); 87 if (lcp == 0) 88 error = ENOBUFS; 89 break; 90 91 /* 92 * Detach a logical channel from the socket. If the state of the 93 * channel is embryonic, simply discard it. Otherwise we have to 94 * initiate a PRU_DISCONNECT which will finish later. 95 */ 96 case PRU_DETACH: 97 pk_disconnect (lcp); 98 break; 99 100 /* 101 * Give the socket an address. 102 */ 103 case PRU_BIND: 104 if (nam -> m_len == sizeof (struct x25_sockaddr)) 105 old_to_new (nam); 106 error = pk_bind (lcp, nam); 107 break; 108 109 /* 110 * Prepare to accept connections. 111 */ 112 case PRU_LISTEN: 113 error = pk_listen (lcp); 114 break; 115 116 /* 117 * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL 118 * and mark the socket as connecting. Set timer waiting for 119 * CALL ACCEPT or CLEAR. 120 */ 121 case PRU_CONNECT: 122 if (nam -> m_len == sizeof (struct x25_sockaddr)) 123 old_to_new (nam); 124 if (pk_checksockaddr (nam)) 125 return (EINVAL); 126 error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *)); 127 break; 128 129 /* 130 * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. 131 * The socket will be disconnected when we receive a confirmation 132 * or a clear collision. 133 */ 134 case PRU_DISCONNECT: 135 pk_disconnect (lcp); 136 break; 137 138 /* 139 * Accept an INCOMING CALL. Most of the work has already been done 140 * by pk_input. Just return the callers address to the user. 141 */ 142 case PRU_ACCEPT: 143 if (lcp -> lcd_craddr == NULL) 144 break; 145 bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), 146 sizeof (struct sockaddr_x25)); 147 nam -> m_len = sizeof (struct sockaddr_x25); 148 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 149 new_to_old (nam); 150 break; 151 152 /* 153 * After a receive, we should send a RR. 154 */ 155 case PRU_RCVD: 156 pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1); 157 break; 158 159 /* 160 * Send INTERRUPT packet. 161 */ 162 case PRU_SENDOOB: 163 if (m == 0) { 164 MGETHDR(m, M_WAITOK, MT_OOBDATA); 165 m -> m_pkthdr.len = m -> m_len = 1; 166 *mtod (m, octet *) = 0; 167 } 168 if (m -> m_pkthdr.len > 32) { 169 m_freem (m); 170 error = EMSGSIZE; 171 break; 172 } 173 MCHTYPE(m, MT_OOBDATA); 174 /* FALLTHROUGH */ 175 176 /* 177 * Do send by placing data on the socket output queue. 178 */ 179 case PRU_SEND: 180 if (control) { 181 register struct cmsghdr *ch = mtod (m, struct cmsghdr *); 182 control -> m_len -= sizeof (*ch); 183 control -> m_data += sizeof (*ch); 184 error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level, 185 ch -> cmsg_type, &control); 186 } 187 if (error == 0 && m) 188 error = pk_send (lcp, m); 189 break; 190 191 /* 192 * Abort a virtual circuit. For example all completed calls 193 * waiting acceptance. 194 */ 195 case PRU_ABORT: 196 pk_disconnect (lcp); 197 break; 198 199 /* Begin unimplemented hooks. */ 200 201 case PRU_SHUTDOWN: 202 error = EOPNOTSUPP; 203 break; 204 205 case PRU_CONTROL: 206 error = EOPNOTSUPP; 207 break; 208 209 case PRU_SENSE: 210 #ifdef BSD4_3 211 ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; 212 #else 213 error = EOPNOTSUPP; 214 #endif 215 break; 216 217 /* End unimplemented hooks. */ 218 219 case PRU_SOCKADDR: 220 if (lcp -> lcd_ceaddr == 0) 221 return (EADDRNOTAVAIL); 222 nam -> m_len = sizeof (struct sockaddr_x25); 223 bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), 224 sizeof (struct sockaddr_x25)); 225 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 226 new_to_old (nam); 227 break; 228 229 case PRU_PEERADDR: 230 if (lcp -> lcd_state != DATA_TRANSFER) 231 return (ENOTCONN); 232 nam -> m_len = sizeof (struct sockaddr_x25); 233 bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : 234 (caddr_t)lcp -> lcd_ceaddr, 235 mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); 236 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 237 new_to_old (nam); 238 break; 239 240 /* 241 * Receive INTERRUPT packet. 242 */ 243 case PRU_RCVOOB: 244 if (so -> so_options & SO_OOBINLINE) { 245 register struct mbuf *n = so -> so_rcv.sb_mb; 246 if (n && n -> m_type == MT_OOBDATA) { 247 unsigned len = n -> m_pkthdr.len; 248 so -> so_rcv.sb_mb = n -> m_nextpkt; 249 if (len != n -> m_len && 250 (n = m_pullup (n, len)) == 0) 251 break; 252 m -> m_len = len; 253 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len); 254 m_freem (n); 255 } 256 break; 257 } 258 m -> m_len = 1; 259 *mtod (m, char *) = lcp -> lcd_intrdata; 260 break; 261 262 default: 263 panic ("pk_usrreq"); 264 } 265 release: 266 if (control != NULL) 267 m_freem (control); 268 return (error); 269 } 270 271 /* 272 * If you want to use UBC X.25 level 3 in conjunction with some 273 * other X.25 level 2 driver, have the ifp -> if_ioctl routine 274 * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25. 275 */ 276 /* ARGSUSED */ 277 pk_start (lcp) 278 register struct pklcd *lcp; 279 { 280 pk_output (lcp); 281 return (0); /* XXX pk_output should return a value */ 282 } 283 284 #ifndef _offsetof 285 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 286 #endif 287 struct sockaddr_x25 pk_sockmask = { 288 _offsetof(struct sockaddr_x25, x25_addr[0]), /* x25_len */ 289 0, /* x25_family */ 290 -1, /* x25_net id */ 291 }; 292 293 /*ARGSUSED*/ 294 pk_control (so, cmd, data, ifp) 295 struct socket *so; 296 int cmd; 297 caddr_t data; 298 register struct ifnet *ifp; 299 { 300 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; 301 register struct ifaddr *ifa = 0; 302 register struct x25_ifaddr *ia = 0; 303 struct pklcd *dev_lcp = 0; 304 int error, s, old_maxlcn; 305 unsigned n; 306 307 /* 308 * Find address for this interface, if it exists. 309 */ 310 if (ifp) 311 for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) 312 if (ifa -> ifa_addr -> sa_family == AF_CCITT) 313 break; 314 315 ia = (struct x25_ifaddr *)ifa; 316 switch (cmd) { 317 case SIOCGIFCONF_X25: 318 if (ifa == 0) 319 return (EADDRNOTAVAIL); 320 ifr -> ifr_xc = ia -> ia_xc; 321 return (0); 322 323 case SIOCSIFCONF_X25: 324 if ((so->so_state & SS_PRIV) == 0) 325 return (EPERM); 326 if (ifp == 0) 327 panic ("pk_control"); 328 if (ifa == (struct ifaddr *)0) { 329 register struct mbuf *m; 330 331 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), 332 M_IFADDR, M_WAITOK); 333 if (ia == 0) 334 return (ENOBUFS); 335 bzero ((caddr_t)ia, sizeof (*ia)); 336 if (ifa = ifp -> if_addrlist) { 337 for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next) 338 ; 339 ifa -> ifa_next = &ia -> ia_ifa; 340 } else 341 ifp -> if_addrlist = &ia -> ia_ifa; 342 ifa = &ia -> ia_ifa; 343 ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask; 344 ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr; 345 ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */ 346 ia -> ia_ifp = ifp; 347 ia -> ia_dstaddr.x25_family = AF_CCITT; 348 ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len; 349 } else if (ISISO8802(ifp) == 0) { 350 rtinit (ifa, (int)RTM_DELETE, 0); 351 } 352 old_maxlcn = ia -> ia_maxlcn; 353 ia -> ia_xc = ifr -> ifr_xc; 354 ia -> ia_dstaddr.x25_net = ia -> ia_xc.xc_addr.x25_net; 355 if (ia -> ia_maxlcn != old_maxlcn && old_maxlcn != 0) { 356 /* VERY messy XXX */ 357 register struct pkcb *pkp; 358 FOR_ALL_PKCBS(pkp) 359 if (pkp -> pk_ia == ia) 360 pk_resize (pkp); 361 } 362 /* 363 * Give the interface a chance to initialize if this 364 p * is its first address, and to validate the address. 365 */ 366 ia -> ia_start = pk_start; 367 s = splimp(); 368 if (ifp -> if_ioctl) 369 error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25, 370 (caddr_t) ifa); 371 if (error) 372 ifp -> if_flags &= ~IFF_UP; 373 else if (ISISO8802(ifp) == 0) 374 error = rtinit (ifa, (int)RTM_ADD, RTF_UP); 375 splx (s); 376 return (error); 377 378 default: 379 if (ifp == 0 || ifp -> if_ioctl == 0) 380 return (EOPNOTSUPP); 381 return ((*ifp -> if_ioctl)(ifp, cmd, data)); 382 } 383 } 384 385 pk_ctloutput (cmd, so, level, optname, mp) 386 struct socket *so; 387 struct mbuf **mp; 388 int cmd, level, optname; 389 { 390 register struct mbuf *m = *mp; 391 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 392 int error = EOPNOTSUPP; 393 394 if (m == 0) 395 return (EINVAL); 396 if (cmd == PRCO_SETOPT) switch (optname) { 397 case PK_FACILITIES: 398 if (m == 0) 399 return (EINVAL); 400 lcp -> lcd_facilities = m; 401 *mp = 0; 402 return (0); 403 404 case PK_ACCTFILE: 405 if ((so->so_state & SS_PRIV) == 0) 406 error = EPERM; 407 else if (m -> m_len) 408 error = pk_accton (mtod (m, char *)); 409 else 410 error = pk_accton ((char *)0); 411 break; 412 413 case PK_RTATTACH: 414 error = pk_rtattach (so, m); 415 break; 416 417 case PK_PRLISTEN: 418 error = pk_user_protolisten (mtod (m, u_char *)); 419 } 420 if (*mp) { 421 (void) m_freem (*mp); 422 *mp = 0; 423 } 424 return (error); 425 426 } 427 428 429 /* 430 * Do an in-place conversion of an "old style" 431 * socket address to the new style 432 */ 433 434 static 435 old_to_new (m) 436 register struct mbuf *m; 437 { 438 register struct x25_sockaddr *oldp; 439 register struct sockaddr_x25 *newp; 440 register char *ocp, *ncp; 441 struct sockaddr_x25 new; 442 443 oldp = mtod (m, struct x25_sockaddr *); 444 newp = &new; 445 bzero ((caddr_t)newp, sizeof (*newp)); 446 447 newp -> x25_family = AF_CCITT; 448 newp -> x25_len = sizeof(*newp); 449 newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE) 450 | X25_MQBIT | X25_OLDSOCKADDR; 451 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 452 newp -> x25_opts.op_psize = X25_PS128; 453 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 454 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 455 if (bcmp ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4) != 0) { 456 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 457 newp -> x25_udlen = 4; 458 } 459 ocp = (caddr_t)oldp -> xaddr_userdata; 460 ncp = newp -> x25_udata + 4; 461 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 462 if (newp -> x25_udlen == 0) 463 newp -> x25_udlen = 4; 464 *ncp++ = *ocp++; 465 newp -> x25_udlen++; 466 } 467 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 468 m -> m_len = sizeof (*newp); 469 } 470 471 /* 472 * Do an in-place conversion of a new style 473 * socket address to the old style 474 */ 475 476 static 477 new_to_old (m) 478 register struct mbuf *m; 479 { 480 register struct x25_sockaddr *oldp; 481 register struct sockaddr_x25 *newp; 482 register char *ocp, *ncp; 483 struct x25_sockaddr old; 484 485 oldp = &old; 486 newp = mtod (m, struct sockaddr_x25 *); 487 bzero ((caddr_t)oldp, sizeof (*oldp)); 488 489 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 490 if (newp -> x25_opts.op_psize == X25_PS128) 491 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 492 ocp = (char *)oldp -> xaddr_addr; 493 ncp = newp -> x25_addr; 494 while (*ncp) { 495 *ocp++ = *ncp++; 496 oldp -> xaddr_len++; 497 } 498 499 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 500 if (newp -> x25_udlen > 4) 501 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 502 (unsigned)(newp -> x25_udlen - 4)); 503 504 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 505 m -> m_len = sizeof (*oldp); 506 } 507 508 509 pk_checksockaddr (m) 510 struct mbuf *m; 511 { 512 register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); 513 register char *cp; 514 515 if (m -> m_len != sizeof (struct sockaddr_x25)) 516 return (1); 517 if (sa -> x25_family != AF_CCITT || 518 sa -> x25_udlen > sizeof (sa -> x25_udata)) 519 return (1); 520 for (cp = sa -> x25_addr; *cp; cp++) { 521 if (*cp < '0' || *cp > '9' || 522 cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) 523 return (1); 524 } 525 return (0); 526 } 527 528 pk_send (lcp, m) 529 struct pklcd *lcp; 530 register struct mbuf *m; 531 { 532 int mqbit = 0, error = 0; 533 register struct x25_packet *xp; 534 register struct socket *so; 535 536 if (m -> m_type == MT_OOBDATA) { 537 if (lcp -> lcd_intrconf_pending) 538 error = ETOOMANYREFS; 539 if (m -> m_pkthdr.len > 32) 540 error = EMSGSIZE; 541 M_PREPEND(m, PKHEADERLN, M_WAITOK); 542 if (m == 0 || error) 543 goto bad; 544 *(mtod (m, octet *)) = 0; 545 xp = mtod (m, struct x25_packet *); 546 X25SBITS(xp -> bits, fmt_identifier, 1); 547 xp -> packet_type = X25_INTERRUPT; 548 SET_LCN(xp, lcp -> lcd_lcn); 549 sbinsertoob ( (so = lcp -> lcd_so) ? 550 &so -> so_snd : &lcp -> lcd_sb, m); 551 goto send; 552 } 553 /* 554 * Application has elected (at call setup time) to prepend 555 * a control byte to each packet written indicating m-bit 556 * and q-bit status. Examine and then discard this byte. 557 */ 558 if (lcp -> lcd_flags & X25_MQBIT) { 559 if (m -> m_len < 1) { 560 m_freem (m); 561 return (EMSGSIZE); 562 } 563 mqbit = *(mtod (m, u_char *)); 564 m -> m_len--; 565 m -> m_data++; 566 m -> m_pkthdr.len--; 567 } 568 error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1); 569 send: 570 if (error == 0 && lcp -> lcd_state == DATA_TRANSFER) 571 lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */ 572 return (error); 573 bad: 574 if (m) 575 m_freem (m); 576 return (error); 577 } 578