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.6 (Berkeley) 08/30/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; 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 lcp->lcd_upnext = (caddr_t)lx; 118 lcp->lcd_upper = x25_ifinput; 119 } 120 switch (lx->lx_state) { 121 122 case LXS_CONNECTED: 123 lcp->lcd_dg_timer = ia->ia_xc.xc_dg_idletimo; 124 /* FALLTHROUGH */ 125 case LXS_CONNECTING: 126 if (sbspace(&lcp->lcd_sb) < 0) 127 senderr(ENOBUFS); 128 lcp->lcd_send(lcp, m); 129 break; 130 131 case LXS_NEWBORN: 132 if (dst->sa_family == AF_INET && 133 ia->ia_ifp->if_type == IFT_X25DDN && 134 rt->rt_gateway->sa_family != AF_CCITT) 135 x25_ddnip_to_ccitt(dst, rt->rt_gateway); 136 lcp->lcd_flags |= X25_DG_CIRCUIT; 137 lx->lx_state = LXS_FREE; 138 if (rt->rt_gateway->sa_family != AF_CCITT) { 139 /* 140 * Need external resolution of dst 141 */ 142 if ((rt->rt_flags & RTF_XRESOLVE) == 0) 143 senderr(ENETUNREACH); 144 lx->lx_flags |= flags; 145 flags = 0; 146 rt_missmsg(RTM_RESOLVE, dst, 147 (struct sockaddr *)0, (struct sockaddr *)0, 148 (struct sockaddr *)0, 0, 0); 149 lx->lx_state = LXS_RESOLVING; 150 /* FALLTHROUGH */ 151 case LXS_RESOLVING: 152 if (sbspace(&lcp->lcd_sb) < 0) 153 senderr(ENOBUFS); 154 sbappendrecord(&lcp->lcd_sb, m); 155 break; 156 } 157 /* FALLTHROUGH */ 158 case LXS_FREE: 159 sbappendrecord(&lcp->lcd_sb, m); 160 lcp->lcd_pkp = &(lx->lx_ia->ia_pkcb); 161 pk_connect(lcp, (struct mbuf *)0, 162 (struct sockaddr_x25 *)rt->rt_gateway); 163 break; 164 /* FALLTHROUGH */ 165 default: 166 /* 167 * We count on the timer routine to close idle 168 * connections, if there are not enough circuits to go 169 * around. 170 * 171 * So throw away data for now. 172 * After we get it all working, we'll rewrite to handle 173 * actively closing connections (other than by timers), 174 * when circuits get tight. 175 * 176 * In the DDN case, the imp itself closes connections 177 * under heavy load. 178 */ 179 error = ENOBUFS; 180 bad: 181 if (m) 182 m_freem(m); 183 } 184 out: 185 if (flags & LXF_RTHELD) 186 RTFREE(rt); 187 return (error); 188 } 189 190 /* 191 * Simpleminded timer routine. 192 */ 193 x25_iftimeout(ifp) 194 struct ifnet *ifp; 195 { 196 register struct pkcb *pkcb = 0; 197 register struct ifaddr *ifa; 198 register struct pklcd **lcpp, *lcp; 199 int s = splimp(); 200 201 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) { 202 if (ifa->ifa_addr->sa_family == AF_CCITT) 203 break; 204 } 205 if (ifa) 206 pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb; 207 if (pkcb) 208 for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; 209 --lcpp >= pkcb->pk_chan;) 210 if ((lcp = *lcpp) && 211 lcp->lcd_state == DATA_TRANSFER && 212 (lcp->lcd_flags & X25_DG_CIRCUIT) && 213 (--(lcp->lcd_dg_timer) <= 0)) { 214 register struct llinfo_x25 *lx; 215 pk_disconnect(lcp); 216 lx = (struct llinfo_x25 *) 217 lcp->lcd_upnext; 218 if (lx) 219 lx->lx_state = LXS_DISCONNECTING; 220 } 221 splx(s); 222 } 223 224 /* 225 * Process a x25 packet as datagram; 226 */ 227 x25_ifinput(lcp, m) 228 struct pklcd *lcp; 229 struct mbuf *m; 230 { 231 struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; 232 struct rtentry *rt = lx->lx_rt; 233 register struct ifnet *ifp = rt->rt_ifp; 234 struct ifqueue *inq; 235 extern struct timeval time; 236 int s; 237 238 ifp->if_lastchange = time; 239 240 switch ((rt_key(rt))->sa_family) { 241 #ifdef INET 242 case AF_INET: 243 schednetisr(NETISR_IP); 244 inq = &ipintrq; 245 break; 246 247 #endif 248 #ifdef NS 249 case AF_NS: 250 schednetisr(NETISR_NS); 251 inq = &nsintrq; 252 break; 253 254 #endif 255 #ifdef ISO 256 case AF_ISO: 257 /* XXXX need to find out about tearing off COSNS 258 headers if any */ 259 schednetisr(NETISR_ISO); 260 inq = &clnlintrq; 261 break; 262 #endif 263 default: 264 m_freem(m); 265 ifp->if_noproto++; 266 return; 267 } 268 s = splimp(); 269 if (IF_QFULL(inq)) { 270 IF_DROP(inq); 271 m_freem(m); 272 } else { 273 IF_ENQUEUE(inq, m); 274 ifp->if_ibytes += m->m_pkthdr.len; 275 } 276 splx(s); 277 } 278 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; 279 /* 280 * IP to X25 address routine copyright ACC, used by permission. 281 */ 282 x25_ddnip_to_ccitt(src, dst) 283 struct sockaddr_in *src; 284 register struct sockaddr_x25 *dst; 285 { 286 union imp_addr imp_addr; 287 int imp_no, imp_port, temp; 288 char *x25addr = dst->x25_addr; 289 290 291 imp_addr.ip = src->sin_addr; 292 *dst = blank_x25; 293 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 294 imp_no = imp_addr.imp.s_impno; 295 imp_port = imp_addr.imp.s_host; 296 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 297 imp_no = imp_addr.imp.s_impno; 298 imp_port = imp_addr.imp.s_lh; 299 } else { /* class C */ 300 imp_no = imp_addr.imp.s_impno / 32; 301 imp_port = imp_addr.imp.s_impno % 32; 302 } 303 304 x25addr[0] = 12; /* length */ 305 /* DNIC is cleared by struct copy above */ 306 307 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 308 * -> III, s_host -> HH */ 309 x25addr[5] = 0; /* set flag bit */ 310 x25addr[6] = imp_no / 100; 311 x25addr[7] = (imp_no % 100) / 10; 312 x25addr[8] = imp_no % 10; 313 x25addr[9] = imp_port / 10; 314 x25addr[10] = imp_port % 10; 315 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 316 * _host * 256 + s_impno -> RRRRR */ 317 temp = (imp_port << 8) + imp_no; 318 x25addr[5] = 1; 319 x25addr[6] = temp / 10000; 320 x25addr[7] = (temp % 10000) / 1000; 321 x25addr[8] = (temp % 1000) / 100; 322 x25addr[9] = (temp % 100) / 10; 323 x25addr[10] = temp % 10; 324 } 325 } 326 327 #ifdef caseof 328 #undef caseof 329 #endif 330 #define caseof(a, b) (b + 8 * a) 331 #define SA(p) ((struct sockaddr *)(p)) 332 333 /* 334 * This routine gets called when validing new routes or deletions of old 335 * ones. 336 */ 337 x25_ifrtchange(cmd, rt, dst) 338 register struct rtentry *rt; 339 struct sockaddr *dst; 340 { 341 register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; 342 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; 343 register struct pklcd *lcp; 344 register struct x25_ifaddr *ia; 345 register struct sockaddr *sa2; 346 struct mbuf *m, *mold; 347 int x25_ifrtfree(); 348 349 if (lx == 0) 350 return; 351 ia = lx->lx_ia; 352 lcp = lx->lx_lcd; 353 354 switch (caseof(lx->lx_state, cmd)) { 355 356 case caseof(LXS_CONNECTED, RTM_DELETE): 357 case caseof(LXS_CONNECTED, RTM_CHANGE): 358 case caseof(LXS_CONNECTING, RTM_DELETE): 359 case caseof(LXS_CONNECTING, RTM_CHANGE): 360 pk_disconnect(lcp); 361 lcp->lcd_upper = x25_ifrtfree; 362 rt->rt_refcnt++; 363 break; 364 365 case caseof(LXS_CONNECTED, RTM_ADD): 366 case caseof(LXS_CONNECTING, RTM_ADD): 367 case caseof(LXS_RESOLVING, RTM_ADD): 368 printf("ifrtchange: impossible transition, should panic\n"); 369 break; 370 371 case caseof(LXS_RESOLVING, RTM_DELETE): 372 sbflush(&(lx->lx_lcd->lcd_sb)); 373 free((caddr_t)lx->lx_lcd, M_PCB); 374 lx->lx_lcd = 0; 375 break; 376 377 case caseof(LXS_RESOLVING, RTM_CHANGE): 378 lcp->lcd_pkp = &(ia->ia_pkcb); 379 pk_connect(lcp, (struct mbuf *)0, sa); 380 break; 381 } 382 if (rt->rt_ifp->if_type == IFT_X25DDN) 383 return; 384 sa2 = rt_key(rt); 385 if (cmd == RTM_CHANGE) { 386 if (sa->x25_family == AF_CCITT) { 387 sa->x25_opts.op_speed = sa2->sa_family; 388 (void) rtrequest(RTM_DELETE, SA(sa), sa2, 389 SA(0), RTF_HOST, (struct rtentry **)0); 390 } 391 sa = (struct sockaddr_x25 *)dst; 392 cmd = RTM_ADD; 393 } 394 if (sa->x25_family == AF_CCITT) { 395 sa->x25_opts.op_speed = sa2->sa_family; 396 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST, 397 (struct rtentry **)0); 398 sa->x25_opts.op_speed = 0; 399 } 400 } 401 402 static struct sockaddr_in sin = {sizeof(sin), AF_INET}; 403 /* 404 * This is a utility routine to be called by x25 devices when a 405 * call request is honored with the intent of starting datagram forwarding. 406 */ 407 x25_dg_rtinit(dst, ia, af) 408 struct sockaddr_x25 *dst; 409 register struct x25_ifaddr *ia; 410 { 411 struct sockaddr *sa = 0; 412 struct rtentry *rt; 413 struct in_addr my_addr; 414 415 if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { 416 /* 417 * Inverse X25 to IP mapping copyright and courtesy ACC. 418 */ 419 int imp_no, imp_port, temp; 420 union imp_addr imp_addr; 421 { 422 /* 423 * First determine our IP addr for network 424 */ 425 register struct in_ifaddr *ina; 426 extern struct in_ifaddr *in_ifaddr; 427 428 for (ina = in_ifaddr; ina; ina = ina->ia_next) 429 if (ina->ia_ifp == ia->ia_ifp) { 430 my_addr = ina->ia_addr.sin_addr; 431 break; 432 } 433 } 434 { 435 436 register char *x25addr = dst->x25_addr; 437 438 switch (x25addr[5] & 0x0f) { 439 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 440 imp_no = 441 ((int) (x25addr[6] & 0x0f) * 100) + 442 ((int) (x25addr[7] & 0x0f) * 10) + 443 ((int) (x25addr[8] & 0x0f)); 444 445 446 imp_port = 447 ((int) (x25addr[9] & 0x0f) * 10) + 448 ((int) (x25addr[10] & 0x0f)); 449 break; 450 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 451 temp = ((int) (x25addr[6] & 0x0f) * 10000) 452 + ((int) (x25addr[7] & 0x0f) * 1000) 453 + ((int) (x25addr[8] & 0x0f) * 100) 454 + ((int) (x25addr[9] & 0x0f) * 10) 455 + ((int) (x25addr[10] & 0x0f)); 456 457 imp_port = temp >> 8; 458 imp_no = temp & 0xff; 459 break; 460 default: 461 return (0L); 462 } 463 imp_addr.ip = my_addr; 464 if ((imp_addr.imp.s_net & 0x80) == 0x00) { 465 /* class A */ 466 imp_addr.imp.s_host = imp_port; 467 imp_addr.imp.s_impno = imp_no; 468 imp_addr.imp.s_lh = 0; 469 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { 470 /* class B */ 471 imp_addr.imp.s_lh = imp_port; 472 imp_addr.imp.s_impno = imp_no; 473 } else { 474 /* class C */ 475 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 476 } 477 } 478 sin.sin_addr = imp_addr.ip; 479 sa = (struct sockaddr *)&sin; 480 } else { 481 /* 482 * This uses the X25 routing table to do inverse 483 * lookup of x25 address to sockaddr. 484 */ 485 dst->x25_opts.op_speed = af; 486 if (rt = rtalloc1(dst, 0)) { 487 sa = rt->rt_gateway; 488 rt->rt_refcnt--; 489 } 490 dst->x25_opts.op_speed = 0; 491 } 492 /* 493 * Call to rtalloc1 will create rtentry for reverse path 494 * to callee by virtue of cloning magic and will allocate 495 * space for local control block. 496 */ 497 if (sa && (rt = rtalloc1(sa, 1))) 498 rt->rt_refcnt--; 499 } 500 501 struct radix_tree_head *x25_rnhead; 502 503 pk_init() 504 { 505 /* 506 * warning, sizeof (struct sockaddr_x25) > 32, 507 * but contains no data of interest beyond 32 508 */ 509 rn_inithead(&x25_rnhead, 16, AF_CCITT); 510 } 511