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