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