1 /* 2 * Copyright (c) University of British Columbia, 1984 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Laboratory for Computation Vision and the Computer Science Department 8 * of the University of British Columbia. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)pk_usrreq.c 7.2 (Berkeley) 05/11/90 13 */ 14 15 #include "../h/param.h" 16 #include "../h/systm.h" 17 #include "../h/mbuf.h" 18 #include "../h/socket.h" 19 #include "../h/protosw.h" 20 #include "../h/socketvar.h" 21 #include "../h/errno.h" 22 #ifdef BSD4_3 23 #include "../net/if.h" 24 #include "ioctl.h" 25 #include "dir.h" 26 #include "user.h" 27 #include "stat.h" 28 #endif 29 30 #include "../netccitt/x25.h" 31 #include "../netccitt/pk.h" 32 #include "../netccitt/pk_var.h" 33 34 struct x25_packet *pk_template (); 35 36 /* 37 * 38 * X.25 Packet level protocol interface to socket abstraction. 39 * 40 * Process an X.25 user request on a logical channel. If this is a send 41 * request then m is the mbuf chain of the send data. If this is a timer 42 * expiration (called from the software clock routine) them timertype is 43 * the particular timer. 44 * 45 */ 46 47 pk_usrreq (so, req, m, nam, rights) 48 struct socket *so; 49 int req; 50 register struct mbuf *m, *nam; 51 struct mbuf *rights; 52 { 53 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 54 register struct x25_packet *xp; 55 register int s = splnet (), error = 0; 56 57 #ifdef BSD4_3 58 if (req == PRU_CONTROL) { 59 error = pk_control(so, (int)m, (caddr_t)nam, 60 (struct ifnet *)rights); 61 splx (s); 62 return (error); 63 } 64 #endif 65 if (rights && rights -> m_len) { 66 splx (s); 67 return (EINVAL); 68 } 69 70 /* 71 pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, 72 req, (struct x25_packet *)0); 73 */ 74 75 if (lcp == NULL && req != PRU_ATTACH) { 76 splx (s); 77 return (EINVAL); 78 } 79 80 switch (req) { 81 /* 82 * X.25 attaches to socket via PRU_ATTACH and allocates a logical 83 * channel descriptor. If the socket is to receive connections, 84 * then the LISTEN state is entered. 85 */ 86 case PRU_ATTACH: 87 if (lcp) { 88 error = EISCONN; 89 /* Socket already connected. */ 90 break; 91 } 92 error = pk_attach (so); 93 break; 94 95 /* 96 * Detach a logical channel from the socket. If the state of the 97 * channel is embryonic, simply discard it. Otherwise we have to 98 * initiate a PRU_DISCONNECT which will finish later. 99 */ 100 case PRU_DETACH: 101 pk_disconnect (lcp); 102 break; 103 104 /* 105 * Give the socket an address. 106 */ 107 case PRU_BIND: 108 if (nam -> m_len == sizeof (struct x25_sockaddr)) 109 old_to_new (nam); 110 error = pk_bind (lcp, nam); 111 break; 112 113 /* 114 * Prepare to accept connections. 115 */ 116 case PRU_LISTEN: 117 if (lcp -> lcd_ceaddr == 0) { 118 error = EDESTADDRREQ; 119 break; 120 } 121 lcp -> lcd_state = LISTEN; 122 lcp -> lcd_listen = pk_listenhead; 123 pk_listenhead = lcp; 124 break; 125 126 /* 127 * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL 128 * and mark the socket as connecting. Set timer waiting for 129 * CALL ACCEPT or CLEAR. 130 */ 131 case PRU_CONNECT: 132 if (nam -> m_len == sizeof (struct x25_sockaddr)) 133 old_to_new (nam); 134 error = pk_connect (lcp, nam); 135 break; 136 137 /* 138 * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. 139 * The socket will be disconnected when we receive a confirmation 140 * or a clear collision. 141 */ 142 case PRU_DISCONNECT: 143 pk_disconnect (lcp); 144 break; 145 146 /* 147 * Accept an INCOMING CALL. Most of the work has already been done 148 * by pk_input. Just return the callers address to the user. 149 */ 150 case PRU_ACCEPT: 151 if (lcp -> lcd_craddr == NULL) 152 break; 153 bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), 154 sizeof (struct sockaddr_x25)); 155 nam -> m_len = sizeof (struct sockaddr_x25); 156 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 157 new_to_old (nam); 158 break; 159 160 /* 161 * After a receive, we should send a RR. 162 */ 163 case PRU_RCVD: 164 lcp -> lcd_rxcnt++; 165 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR); 166 pk_output (lcp); 167 break; 168 169 /* 170 * Do send by placing data on the socket output queue. 171 * SHOULD WE USE m_cat HERE. 172 */ 173 case PRU_SEND: 174 error = pk_send (lcp, m); 175 break; 176 177 /* 178 * Abort a virtual circuit. For example all completed calls 179 * waiting acceptance. 180 */ 181 case PRU_ABORT: 182 pk_disconnect (lcp); 183 break; 184 185 /* Begin unimplemented hooks. */ 186 187 case PRU_SHUTDOWN: 188 error = EOPNOTSUPP; 189 break; 190 191 case PRU_CONTROL: 192 error = EOPNOTSUPP; 193 break; 194 195 case PRU_SENSE: 196 #ifdef BSD4_3 197 ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; 198 #else 199 error = EOPNOTSUPP; 200 #endif 201 break; 202 203 /* End unimplemented hooks. */ 204 205 case PRU_SOCKADDR: 206 if (lcp -> lcd_ceaddr == 0) 207 return (EADDRNOTAVAIL); 208 nam -> m_len = sizeof (struct sockaddr_x25); 209 bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), 210 sizeof (struct sockaddr_x25)); 211 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 212 new_to_old (nam); 213 break; 214 215 case PRU_PEERADDR: 216 if (lcp -> lcd_state != DATA_TRANSFER) 217 return (ENOTCONN); 218 nam -> m_len = sizeof (struct sockaddr_x25); 219 bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : 220 (caddr_t)lcp -> lcd_ceaddr, 221 mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); 222 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 223 new_to_old (nam); 224 break; 225 226 /* 227 * Receive INTERRUPT packet. 228 */ 229 case PRU_RCVOOB: 230 m -> m_len = 1; 231 *mtod (m, char *) = lcp -> lcd_intrdata; 232 break; 233 234 /* 235 * Send INTERRUPT packet. 236 */ 237 case PRU_SENDOOB: 238 m_freem (m); 239 if (lcp -> lcd_intrconf_pending) { 240 error = ETOOMANYREFS; 241 break; 242 } 243 lcp -> lcd_intrcnt++; 244 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT); 245 xp -> packet_data = 0; 246 (dtom (xp)) -> m_len++; 247 pk_output (lcp); 248 break; 249 250 default: 251 panic ("pk_usrreq"); 252 } 253 254 splx (s); 255 return (error); 256 } 257 258 #ifdef BSD4_3 259 /*ARGSUSED*/ 260 pk_control (so, cmd, data, ifp) 261 struct socket *so; 262 int cmd; 263 caddr_t data; 264 register struct ifnet *ifp; 265 { 266 register struct ifreq *ifr = (struct ifreq *)data; 267 register struct ifaddr *ifa = 0; 268 register int error, s; 269 struct sockaddr oldaddr; 270 271 /* 272 * Find address for this interface, if it exists. 273 */ 274 if (ifp) 275 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 276 if (ifa->ifa_addr.sa_family == AF_CCITT) 277 break; 278 279 switch (cmd) { 280 case SIOCGIFADDR: 281 if (ifa == 0) 282 return (EADDRNOTAVAIL); 283 ifr -> ifr_addr = ifa->ifa_addr; 284 return (0); 285 286 case SIOCSIFADDR: 287 if (!suser()) 288 return (u.u_error); 289 290 if (ifp == 0) 291 panic("pk_control"); 292 if (ifa == (struct ifaddr *)0) { 293 register struct ifaddr *ia; 294 register struct mbuf *m; 295 296 m = m_getclr(M_WAIT, MT_IFADDR); 297 if (m == (struct mbuf *)NULL) 298 return (ENOBUFS); 299 ia = mtod(m, struct ifaddr *); 300 if (ifa = ifp->if_addrlist) { 301 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 302 ; 303 ifa->ifa_next = ia; 304 } else 305 ifp->if_addrlist = ia; 306 ifa = ia; 307 ifa->ifa_ifp = ifp; 308 } 309 oldaddr = ifa->ifa_addr; 310 s = splimp(); 311 ifa->ifa_addr = ifr->ifr_addr; 312 /* 313 * Give the interface a chance to initialize if this 314 * is its first address, and to validate the address. 315 */ 316 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ifa))) { 317 splx(s); 318 ifa->ifa_addr = oldaddr; 319 return (error); 320 } 321 splx(s); 322 #ifndef WATERLOO 323 (void) pk_accton (); 324 #endif 325 return (0); 326 327 default: 328 if (ifp == 0 || ifp->if_ioctl == 0) 329 return (EOPNOTSUPP); 330 return ((*ifp->if_ioctl)(ifp, cmd, data)); 331 } 332 } 333 #endif 334 335 /* 336 * Do an in-place conversion of an "old style" 337 * socket address to the new style 338 */ 339 340 static 341 old_to_new (m) 342 register struct mbuf *m; 343 { 344 register struct x25_sockaddr *oldp; 345 register struct sockaddr_x25 *newp; 346 register char *ocp, *ncp; 347 struct sockaddr_x25 new; 348 349 oldp = mtod (m, struct x25_sockaddr *); 350 newp = &new; 351 bzero ((caddr_t)newp, sizeof (*newp)); 352 353 newp -> x25_family = AF_CCITT; 354 newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 355 | X25_MQBIT | X25_OLDSOCKADDR; 356 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 357 newp -> x25_opts.op_psize = X25_PS128; 358 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 359 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 360 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 361 newp -> x25_udlen = 4; 362 363 ocp = (caddr_t)oldp -> xaddr_userdata; 364 ncp = newp -> x25_udata + 4; 365 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 366 *ncp++ = *ocp++; 367 newp -> x25_udlen++; 368 } 369 370 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 371 m->m_len = sizeof (*newp); 372 } 373 374 /* 375 * Do an in-place conversion of a new style 376 * socket address to the old style 377 */ 378 379 static 380 new_to_old (m) 381 register struct mbuf *m; 382 { 383 register struct x25_sockaddr *oldp; 384 register struct sockaddr_x25 *newp; 385 register char *ocp, *ncp; 386 struct x25_sockaddr old; 387 388 oldp = &old; 389 newp = mtod (m, struct sockaddr_x25 *); 390 bzero ((caddr_t)oldp, sizeof (*oldp)); 391 392 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 393 if (newp -> x25_opts.op_psize == X25_PS128) 394 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 395 ocp = (char *)oldp -> xaddr_addr; 396 ncp = newp -> x25_addr; 397 while (*ncp) { 398 *ocp++ = *ncp++; 399 oldp -> xaddr_len++; 400 } 401 402 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 403 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 404 (unsigned)(newp -> x25_udlen - 4)); 405 406 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 407 m -> m_len = sizeof (*oldp); 408 } 409 410 pk_send (lcp, m) 411 register struct pklcd *lcp; 412 register struct mbuf *m; 413 { 414 register struct x25_packet *xp; 415 register struct mbuf *m0; 416 register int len; 417 418 m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 419 m0 -> m_next = m; 420 /* 421 * Application has elected (at call setup time) to prepend 422 * a control byte to each packet written indicating m-bit 423 * and q-bit status. Examine and then discard this byte. 424 */ 425 if (lcp -> lcd_flags & X25_MQBIT) { 426 register octet *cp; 427 428 if (m -> m_len < 1) { 429 m_freem (m0); 430 return (EMSGSIZE); 431 } 432 cp = mtod (m, octet *); 433 if (*cp & 0x80) /* XXX */ 434 xp -> q_bit = 1; 435 xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 436 m -> m_len--; 437 m -> m_off++; 438 } 439 len = m -> m_len; 440 while (m -> m_next) { 441 m = m -> m_next; 442 len += m -> m_len; 443 } 444 if (len > (1 << lcp -> lcd_packetsize)) { 445 m_freem (m0); 446 return (EMSGSIZE); 447 } 448 449 #ifdef BSD4_3 450 sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 451 #else 452 m -> m_act = (struct mbuf *) 1; 453 sbappend (&lcp -> lcd_so -> so_snd, m0); 454 #endif 455 lcp -> lcd_template = 0; 456 lcp -> lcd_txcnt++; 457 pk_output (lcp); 458 return (0); 459 } 460