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