1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_x25subr.c 7.7 (Berkeley) 10/04/90 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "malloc.h" 13 #include "mbuf.h" 14 #include "protosw.h" 15 #include "socket.h" 16 #include "socketvar.h" 17 #include "ioctl.h" 18 #include "errno.h" 19 #include "syslog.h" 20 21 #include "../net/if.h" 22 #include "../net/if_types.h" 23 #include "../net/netisr.h" 24 #include "../net/route.h" 25 26 #include "x25.h" 27 #include "x25err.h" 28 #include "pk.h" 29 #include "pk_var.h" 30 31 #include "machine/mtpr.h" 32 33 #ifdef INET 34 #include "../netinet/in.h" 35 #include "../netinet/in_var.h" 36 #endif 37 38 #ifdef NS 39 #include "../netns/ns.h" 40 #include "../netns/ns_if.h" 41 #endif 42 43 #ifdef ISO 44 #include "../netiso/argo_debug.h" 45 #include "../netiso/iso.h" 46 #include "../netiso/iso_var.h" 47 #endif 48 49 extern struct ifnet loif; 50 51 union imp_addr { 52 struct in_addr ip; 53 struct imp { 54 u_char s_net; 55 u_char s_host; 56 u_char s_lh; 57 u_char s_impno; 58 } imp; 59 }; 60 61 #define senderr(x) {error = x; goto bad;} 62 /* 63 * X.25 output routine. 64 */ 65 x25_ifoutput(ifp, m0, dst, rt) 66 struct ifnet *ifp; 67 struct mbuf *m0; 68 struct sockaddr *dst; 69 register struct rtentry *rt; 70 { 71 register struct mbuf *m; 72 register struct llinfo_x25 *lx; 73 register struct pq *pq; 74 struct pklcd *lcp; 75 struct x25_ifaddr *ia; 76 struct mbuf *prev; 77 int s, error = 0, flags = 0, af; 78 union imp_addr imp_addr; 79 80 if ((ifp->if_flags & IFF_UP) == 0) 81 return (ENETDOWN); 82 if (rt == 0 || 83 ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) { 84 if ((rt = rtalloc1(dst, 1)) == 0) 85 return (EHOSTUNREACH); 86 rt->rt_refcnt++; 87 flags = LXF_RTHELD; 88 } 89 /* 90 * Sanity checks. 91 */ 92 if ((rt->rt_ifp != ifp) || 93 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || 94 ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { 95 printf("Inconsistent call to x25_output, should panic\n"); 96 senderr(ENETUNREACH); 97 } 98 { 99 register struct ifaddr *ifa; 100 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) { 101 if (ifa == 0) 102 senderr(ENETDOWN); 103 if (ifa->ifa_addr->sa_family == AF_CCITT) 104 break; 105 } 106 ia = (struct x25_ifaddr *)ifa; 107 } 108 if (lx->lx_lcd == 0) { 109 int x25_ifinput(); 110 111 lcp = pk_attach((struct socket *)0); 112 if (lcp == 0) 113 senderr(ENOBUFS); 114 lx->lx_lcd = lcp; 115 lx->lx_rt = rt; 116 lx->lx_ia = ia; 117 lx->lx_family = dst->sa_family; 118 lcp->lcd_upnext = (caddr_t)lx; 119 lcp->lcd_upper = x25_ifinput; 120 lcp->lcd_packetsize = ia->ia_xc.xc_psize; /* XXX pk_fragment */ 121 } 122 switch (lx->lx_state) { 123 124 case LXS_CONNECTED: 125 lcp->lcd_dg_timer = ia->ia_xc.xc_dg_idletimo; 126 /* FALLTHROUGH */ 127 case LXS_CONNECTING: 128 if (sbspace(&lcp->lcd_sb) < 0) 129 senderr(ENOBUFS); 130 lcp->lcd_send(lcp, m); 131 break; 132 133 case LXS_NEWBORN: 134 if (dst->sa_family == AF_INET && 135 ia->ia_ifp->if_type == IFT_X25DDN && 136 rt->rt_gateway->sa_family != AF_CCITT) 137 x25_ddnip_to_ccitt(dst, rt->rt_gateway); 138 lcp->lcd_flags |= X25_DG_CIRCUIT; 139 lx->lx_state = LXS_FREE; 140 if (rt->rt_gateway->sa_family != AF_CCITT) { 141 /* 142 * Need external resolution of dst 143 */ 144 if ((rt->rt_flags & RTF_XRESOLVE) == 0) 145 senderr(ENETUNREACH); 146 lx->lx_flags |= flags; 147 flags = 0; 148 rt_missmsg(RTM_RESOLVE, dst, 149 (struct sockaddr *)0, (struct sockaddr *)0, 150 (struct sockaddr *)0, 0, 0); 151 lx->lx_state = LXS_RESOLVING; 152 /* FALLTHROUGH */ 153 case LXS_RESOLVING: 154 if (sbspace(&lcp->lcd_sb) < 0) 155 senderr(ENOBUFS); 156 pk_fragment(lcp, m, 0, 0, 0); 157 break; 158 } 159 /* FALLTHROUGH */ 160 case LXS_FREE: 161 lcp->lcd_pkp = &(lx->lx_ia->ia_pkcb); 162 pk_fragment(lcp, m, 0, 0, 0); 163 pk_connect(lcp, (struct mbuf *)0, 164 (struct sockaddr_x25 *)rt->rt_gateway); 165 break; 166 /* FALLTHROUGH */ 167 default: 168 /* 169 * We count on the timer routine to close idle 170 * connections, if there are not enough circuits to go 171 * around. 172 * 173 * So throw away data for now. 174 * After we get it all working, we'll rewrite to handle 175 * actively closing connections (other than by timers), 176 * when circuits get tight. 177 * 178 * In the DDN case, the imp itself closes connections 179 * under heavy load. 180 */ 181 error = ENOBUFS; 182 bad: 183 if (m) 184 m_freem(m); 185 } 186 out: 187 if (flags & LXF_RTHELD) 188 RTFREE(rt); 189 return (error); 190 } 191 192 /* 193 * Simpleminded timer routine. 194 */ 195 x25_iftimeout(ifp) 196 struct ifnet *ifp; 197 { 198 register struct pkcb *pkcb = 0; 199 register struct ifaddr *ifa; 200 register struct pklcd **lcpp, *lcp; 201 int s = splimp(); 202 203 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) { 204 if (ifa->ifa_addr->sa_family == AF_CCITT) 205 break; 206 } 207 if (ifa) 208 pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb; 209 if (pkcb) 210 for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; 211 --lcpp >= pkcb->pk_chan;) 212 if ((lcp = *lcpp) && 213 lcp->lcd_state == DATA_TRANSFER && 214 (lcp->lcd_flags & X25_DG_CIRCUIT) && 215 (--(lcp->lcd_dg_timer) <= 0)) { 216 register struct llinfo_x25 *lx; 217 pk_disconnect(lcp); 218 lx = (struct llinfo_x25 *) 219 lcp->lcd_upnext; 220 if (lx) 221 lx->lx_state = LXS_DISCONNECTING; 222 } 223 splx(s); 224 } 225 226 /* 227 * Process a x25 packet as datagram; 228 */ 229 x25_ifinput(lcp, m) 230 struct pklcd *lcp; 231 register struct mbuf *m; 232 { 233 struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; 234 struct rtentry *rt = lx->lx_rt; 235 register struct ifnet *ifp = rt->rt_ifp; 236 struct ifqueue *inq; 237 extern struct timeval time; 238 struct x25_packet *xp = mtod(m, struct x25_packet *); 239 struct mbuf **mp = &lcp->lcd_ifrag; 240 int s, len; 241 242 ifp->if_lastchange = time; 243 switch (m->m_type) { 244 case MT_CONTROL: 245 case MT_OOBDATA: 246 m_freem(m); 247 return; 248 249 case MT_DATA: 250 case MT_HEADER: 251 m->m_len -= PKHEADERLN; 252 m->m_data += PKHEADERLN; 253 m->m_pkthdr.len -= PKHEADERLN; 254 while (*mp) 255 mp = &((*mp)->m_next); 256 *mp = m; 257 if (MBIT(xp)) 258 return; 259 } 260 m = lcp->lcd_ifrag; 261 if (m->m_flags & M_PKTHDR) { 262 for (len = 0; m; m = m->m_next) 263 len += m->m_len; 264 m = lcp->lcd_ifrag; 265 m->m_pkthdr.len = len; 266 } 267 268 switch (lx->lx_family) { 269 #ifdef INET 270 case AF_INET: 271 schednetisr(NETISR_IP); 272 inq = &ipintrq; 273 break; 274 275 #endif 276 #ifdef NS 277 case AF_NS: 278 schednetisr(NETISR_NS); 279 inq = &nsintrq; 280 break; 281 282 #endif 283 #ifdef ISO 284 case AF_ISO: 285 /* XXXX need to find out about tearing off COSNS 286 headers if any */ 287 schednetisr(NETISR_ISO); 288 inq = &clnlintrq; 289 break; 290 #endif 291 default: 292 m_freem(m); 293 ifp->if_noproto++; 294 return; 295 } 296 s = splimp(); 297 if (IF_QFULL(inq)) { 298 IF_DROP(inq); 299 m_freem(m); 300 } else { 301 IF_ENQUEUE(inq, m); 302 ifp->if_ibytes += m->m_pkthdr.len; 303 } 304 splx(s); 305 } 306 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; 307 /* 308 * IP to X25 address routine copyright ACC, used by permission. 309 */ 310 x25_ddnip_to_ccitt(src, dst) 311 struct sockaddr_in *src; 312 register struct sockaddr_x25 *dst; 313 { 314 union imp_addr imp_addr; 315 int imp_no, imp_port, temp; 316 char *x25addr = dst->x25_addr; 317 318 319 imp_addr.ip = src->sin_addr; 320 *dst = blank_x25; 321 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 322 imp_no = imp_addr.imp.s_impno; 323 imp_port = imp_addr.imp.s_host; 324 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 325 imp_no = imp_addr.imp.s_impno; 326 imp_port = imp_addr.imp.s_lh; 327 } else { /* class C */ 328 imp_no = imp_addr.imp.s_impno / 32; 329 imp_port = imp_addr.imp.s_impno % 32; 330 } 331 332 x25addr[0] = 12; /* length */ 333 /* DNIC is cleared by struct copy above */ 334 335 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 336 * -> III, s_host -> HH */ 337 x25addr[5] = 0; /* set flag bit */ 338 x25addr[6] = imp_no / 100; 339 x25addr[7] = (imp_no % 100) / 10; 340 x25addr[8] = imp_no % 10; 341 x25addr[9] = imp_port / 10; 342 x25addr[10] = imp_port % 10; 343 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 344 * _host * 256 + s_impno -> RRRRR */ 345 temp = (imp_port << 8) + imp_no; 346 x25addr[5] = 1; 347 x25addr[6] = temp / 10000; 348 x25addr[7] = (temp % 10000) / 1000; 349 x25addr[8] = (temp % 1000) / 100; 350 x25addr[9] = (temp % 100) / 10; 351 x25addr[10] = temp % 10; 352 } 353 } 354 355 #ifdef caseof 356 #undef caseof 357 #endif 358 #define caseof(a, b) (b + 8 * a) 359 #define SA(p) ((struct sockaddr *)(p)) 360 361 /* 362 * This routine gets called when validing new routes or deletions of old 363 * ones. 364 */ 365 x25_ifrtchange(cmd, rt, dst) 366 register struct rtentry *rt; 367 struct sockaddr *dst; 368 { 369 register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; 370 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; 371 register struct pklcd *lcp; 372 register struct x25_ifaddr *ia; 373 register struct sockaddr *sa2; 374 struct mbuf *m, *mold; 375 int x25_ifrtfree(); 376 377 if (lx == 0) 378 return; 379 ia = lx->lx_ia; 380 lcp = lx->lx_lcd; 381 382 switch (caseof(lx->lx_state, cmd)) { 383 384 case caseof(LXS_CONNECTED, RTM_DELETE): 385 case caseof(LXS_CONNECTED, RTM_CHANGE): 386 case caseof(LXS_CONNECTING, RTM_DELETE): 387 case caseof(LXS_CONNECTING, RTM_CHANGE): 388 pk_disconnect(lcp); 389 /*lcp->lcd_upper = x25_ifrtfree; */ 390 rt->rt_refcnt++; 391 break; 392 393 case caseof(LXS_CONNECTED, RTM_ADD): 394 case caseof(LXS_CONNECTING, RTM_ADD): 395 case caseof(LXS_RESOLVING, RTM_ADD): 396 printf("ifrtchange: impossible transition, should panic\n"); 397 break; 398 399 case caseof(LXS_RESOLVING, RTM_DELETE): 400 sbflush(&(lx->lx_lcd->lcd_sb)); 401 free((caddr_t)lx->lx_lcd, M_PCB); 402 lx->lx_lcd = 0; 403 break; 404 405 case caseof(LXS_RESOLVING, RTM_CHANGE): 406 lcp->lcd_pkp = &(ia->ia_pkcb); 407 pk_connect(lcp, (struct mbuf *)0, sa); 408 break; 409 } 410 if (rt->rt_ifp->if_type == IFT_X25DDN) 411 return; 412 sa2 = rt_key(rt); 413 if (cmd == RTM_CHANGE) { 414 if (sa->x25_family == AF_CCITT) { 415 sa->x25_opts.op_speed = sa2->sa_family; 416 (void) rtrequest(RTM_DELETE, SA(sa), sa2, 417 SA(0), RTF_HOST, (struct rtentry **)0); 418 } 419 sa = (struct sockaddr_x25 *)dst; 420 cmd = RTM_ADD; 421 } 422 if (sa->x25_family == AF_CCITT) { 423 sa->x25_opts.op_speed = sa2->sa_family; 424 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST, 425 (struct rtentry **)0); 426 sa->x25_opts.op_speed = 0; 427 } 428 } 429 430 static struct sockaddr_in sin = {sizeof(sin), AF_INET}; 431 /* 432 * This is a utility routine to be called by x25 devices when a 433 * call request is honored with the intent of starting datagram forwarding. 434 */ 435 x25_dg_rtinit(dst, ia, af) 436 struct sockaddr_x25 *dst; 437 register struct x25_ifaddr *ia; 438 { 439 struct sockaddr *sa = 0; 440 struct rtentry *rt; 441 struct in_addr my_addr; 442 443 if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { 444 /* 445 * Inverse X25 to IP mapping copyright and courtesy ACC. 446 */ 447 int imp_no, imp_port, temp; 448 union imp_addr imp_addr; 449 { 450 /* 451 * First determine our IP addr for network 452 */ 453 register struct in_ifaddr *ina; 454 extern struct in_ifaddr *in_ifaddr; 455 456 for (ina = in_ifaddr; ina; ina = ina->ia_next) 457 if (ina->ia_ifp == ia->ia_ifp) { 458 my_addr = ina->ia_addr.sin_addr; 459 break; 460 } 461 } 462 { 463 464 register char *x25addr = dst->x25_addr; 465 466 switch (x25addr[5] & 0x0f) { 467 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 468 imp_no = 469 ((int) (x25addr[6] & 0x0f) * 100) + 470 ((int) (x25addr[7] & 0x0f) * 10) + 471 ((int) (x25addr[8] & 0x0f)); 472 473 474 imp_port = 475 ((int) (x25addr[9] & 0x0f) * 10) + 476 ((int) (x25addr[10] & 0x0f)); 477 break; 478 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 479 temp = ((int) (x25addr[6] & 0x0f) * 10000) 480 + ((int) (x25addr[7] & 0x0f) * 1000) 481 + ((int) (x25addr[8] & 0x0f) * 100) 482 + ((int) (x25addr[9] & 0x0f) * 10) 483 + ((int) (x25addr[10] & 0x0f)); 484 485 imp_port = temp >> 8; 486 imp_no = temp & 0xff; 487 break; 488 default: 489 return (0L); 490 } 491 imp_addr.ip = my_addr; 492 if ((imp_addr.imp.s_net & 0x80) == 0x00) { 493 /* class A */ 494 imp_addr.imp.s_host = imp_port; 495 imp_addr.imp.s_impno = imp_no; 496 imp_addr.imp.s_lh = 0; 497 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { 498 /* class B */ 499 imp_addr.imp.s_lh = imp_port; 500 imp_addr.imp.s_impno = imp_no; 501 } else { 502 /* class C */ 503 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 504 } 505 } 506 sin.sin_addr = imp_addr.ip; 507 sa = (struct sockaddr *)&sin; 508 } else { 509 /* 510 * This uses the X25 routing table to do inverse 511 * lookup of x25 address to sockaddr. 512 */ 513 dst->x25_opts.op_speed = af; 514 if (rt = rtalloc1(dst, 0)) { 515 sa = rt->rt_gateway; 516 rt->rt_refcnt--; 517 } 518 dst->x25_opts.op_speed = 0; 519 } 520 /* 521 * Call to rtalloc1 will create rtentry for reverse path 522 * to callee by virtue of cloning magic and will allocate 523 * space for local control block. 524 */ 525 if (sa && (rt = rtalloc1(sa, 1))) 526 rt->rt_refcnt--; 527 } 528 529 struct radix_tree_head *x25_rnhead; 530 531 pk_init() 532 { 533 /* 534 * warning, sizeof (struct sockaddr_x25) > 32, 535 * but contains no data of interest beyond 32 536 */ 537 rn_inithead(&x25_rnhead, 16, AF_CCITT); 538 } 539