1 /* 2 * Copyright (c) 1982, 1986 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_en.c 7.2 (Berkeley) 08/04/88 18 */ 19 20 #include "en.h" 21 #if NEN > 0 22 23 /* 24 * Xerox prototype (3 Mb) Ethernet interface driver. 25 */ 26 #include "../machine/pte.h" 27 28 #include "param.h" 29 #include "systm.h" 30 #include "mbuf.h" 31 #include "buf.h" 32 #include "protosw.h" 33 #include "socket.h" 34 #include "vmmac.h" 35 #include "errno.h" 36 #include "ioctl.h" 37 38 #include "../net/if.h" 39 #include "../net/netisr.h" 40 #include "../net/route.h" 41 42 #ifdef INET 43 #include "../netinet/in.h" 44 #include "../netinet/in_systm.h" 45 #include "../netinet/in_var.h" 46 #include "../netinet/ip.h" 47 #endif 48 49 #ifdef PUP 50 #include "../netpup/pup.h" 51 #include "../netpup/ether.h" 52 #endif 53 54 #ifdef NS 55 #include "../netns/ns.h" 56 #include "../netns/ns_if.h" 57 #endif 58 59 #include "../vax/cpu.h" 60 #include "../vax/mtpr.h" 61 #include "if_en.h" 62 #include "if_enreg.h" 63 #include "if_uba.h" 64 #include "../vaxuba/ubareg.h" 65 #include "../vaxuba/ubavar.h" 66 67 #define ENMTU (1024+512) 68 #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 69 70 int enprobe(), enattach(), enrint(), enxint(), encollide(); 71 struct uba_device *eninfo[NEN]; 72 u_short enstd[] = { 0 }; 73 struct uba_driver endriver = 74 { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 75 #define ENUNIT(x) minor(x) 76 77 int eninit(),enoutput(),enreset(),enioctl(); 78 79 #ifdef notdef 80 /* 81 * If you need to byte swap IP's in the system, define 82 * this and do a SIOCSIFFLAGS at boot time. 83 */ 84 #define ENF_SWABIPS 0x1000 85 #endif 86 87 /* 88 * Ethernet software status per interface. 89 * 90 * Each interface is referenced by a network interface structure, 91 * es_if, which the routing code uses to locate the interface. 92 * This structure contains the output queue for the interface, its address, ... 93 * We also have, for each interface, a UBA interface structure, which 94 * contains information about the UNIBUS resources held by the interface: 95 * map registers, buffered data paths, etc. Information is cached in this 96 * structure for use by the if_uba.c routines in running the interface 97 * efficiently. 98 */ 99 struct en_softc { 100 struct ifnet es_if; /* network-visible interface */ 101 struct ifuba es_ifuba; /* UNIBUS resources */ 102 short es_host; /* hardware host number */ 103 short es_delay; /* current output delay */ 104 short es_mask; /* mask for current output delay */ 105 short es_lastx; /* host last transmitted to */ 106 short es_oactive; /* is output active? */ 107 short es_olen; /* length of last output */ 108 short es_nsactive; /* is interface enabled for ns? */ 109 } en_softc[NEN]; 110 111 /* 112 * Do output DMA to determine interface presence and 113 * interrupt vector. DMA is too short to disturb other hosts. 114 */ 115 enprobe(reg) 116 caddr_t reg; 117 { 118 register int br, cvec; /* r11, r10 value-result */ 119 register struct endevice *addr = (struct endevice *)reg; 120 121 #ifdef lint 122 br = 0; cvec = br; br = cvec; 123 enrint(0); enxint(0); encollide(0); 124 #endif 125 addr->en_istat = 0; 126 addr->en_owc = -1; 127 addr->en_oba = 0; 128 addr->en_ostat = EN_IEN|EN_GO; 129 DELAY(100000); 130 addr->en_ostat = 0; 131 return (1); 132 } 133 134 /* 135 * Interface exists: make available by filling in network interface 136 * record. System will initialize the interface when it is ready 137 * to accept packets. 138 */ 139 enattach(ui) 140 struct uba_device *ui; 141 { 142 register struct en_softc *es = &en_softc[ui->ui_unit]; 143 144 es->es_if.if_unit = ui->ui_unit; 145 es->es_if.if_name = "en"; 146 es->es_if.if_mtu = ENMTU; 147 es->es_if.if_flags = IFF_BROADCAST; 148 es->es_if.if_init = eninit; 149 es->es_if.if_output = enoutput; 150 es->es_if.if_ioctl = enioctl; 151 es->es_if.if_reset = enreset; 152 es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 153 #if defined(VAX750) 154 /* don't chew up 750 bdp's */ 155 if (cpu == VAX_750 && ui->ui_unit > 0) 156 es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 157 #endif 158 if_attach(&es->es_if); 159 } 160 161 /* 162 * Reset of interface after UNIBUS reset. 163 * If interface is on specified uba, reset its state. 164 */ 165 enreset(unit, uban) 166 int unit, uban; 167 { 168 register struct uba_device *ui; 169 170 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 171 ui->ui_ubanum != uban) 172 return; 173 printf(" en%d", unit); 174 eninit(unit); 175 } 176 177 /* 178 * Initialization of interface; clear recorded pending 179 * operations, and reinitialize UNIBUS usage. 180 */ 181 eninit(unit) 182 int unit; 183 { 184 register struct en_softc *es = &en_softc[unit]; 185 register struct uba_device *ui = eninfo[unit]; 186 register struct endevice *addr; 187 int s; 188 189 if (es->es_if.if_addrlist == (struct ifaddr *)0) 190 return; 191 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 192 sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 193 printf("en%d: can't initialize\n", unit); 194 es->es_if.if_flags &= ~IFF_UP; 195 return; 196 } 197 addr = (struct endevice *)ui->ui_addr; 198 addr->en_istat = addr->en_ostat = 0; 199 200 /* 201 * Hang a receive and start any 202 * pending writes by faking a transmit complete. 203 */ 204 s = splimp(); 205 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 206 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 207 addr->en_istat = EN_IEN|EN_GO; 208 es->es_oactive = 1; 209 es->es_if.if_flags |= IFF_RUNNING; 210 enxint(unit); 211 splx(s); 212 } 213 214 int enalldelay = 0; 215 int enlastdel = 50; 216 int enlastmask = (~0) << 5; 217 218 /* 219 * Start or restart output on interface. 220 * If interface is already active, then this is a retransmit 221 * after a collision, and just restuff registers and delay. 222 * If interface is not already active, get another datagram 223 * to send off of the interface queue, and map it to the interface 224 * before starting the output. 225 */ 226 enstart(dev) 227 dev_t dev; 228 { 229 int unit = ENUNIT(dev); 230 struct uba_device *ui = eninfo[unit]; 231 register struct en_softc *es = &en_softc[unit]; 232 register struct endevice *addr; 233 register struct en_header *en; 234 struct mbuf *m; 235 int dest; 236 237 if (es->es_oactive) 238 goto restart; 239 240 /* 241 * Not already active: dequeue another request 242 * and map it to the UNIBUS. If no more requests, 243 * just return. 244 */ 245 IF_DEQUEUE(&es->es_if.if_snd, m); 246 if (m == 0) { 247 es->es_oactive = 0; 248 return; 249 } 250 en = mtod(m, struct en_header *); 251 dest = en->en_dhost; 252 en->en_shost = es->es_host; 253 es->es_olen = if_wubaput(&es->es_ifuba, m); 254 #ifdef ENF_SWABIPS 255 /* 256 * The Xerox interface does word at a time DMA, so 257 * someone must do byte swapping of user data if high 258 * and low ender machines are to communicate. It doesn't 259 * belong here, but certain people depend on it, so... 260 * 261 * Should swab everybody, but this is a kludge anyway. 262 */ 263 if (es->es_if.if_flags & ENF_SWABIPS) { 264 en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 265 if (en->en_type == ENTYPE_IP) 266 enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 267 es->es_olen - sizeof (struct en_header) + 1); 268 } 269 #endif 270 271 /* 272 * Ethernet cannot take back-to-back packets (no 273 * buffering in interface. To help avoid overrunning 274 * receivers, enforce a small delay (about 1ms) in interface: 275 * * between all packets when enalldelay 276 * * whenever last packet was broadcast 277 * * whenever this packet is to same host as last packet 278 */ 279 if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 280 es->es_delay = enlastdel; 281 es->es_mask = enlastmask; 282 } 283 es->es_lastx = dest; 284 285 restart: 286 /* 287 * Have request mapped to UNIBUS for transmission. 288 * Purge any stale data from this BDP, and start the otput. 289 */ 290 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 291 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 292 addr = (struct endevice *)ui->ui_addr; 293 addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 294 addr->en_odelay = es->es_delay; 295 addr->en_owc = -((es->es_olen + 1) >> 1); 296 addr->en_ostat = EN_IEN|EN_GO; 297 es->es_oactive = 1; 298 } 299 300 /* 301 * Ethernet interface transmitter interrupt. 302 * Start another output if more data to send. 303 */ 304 enxint(unit) 305 int unit; 306 { 307 register struct uba_device *ui = eninfo[unit]; 308 register struct en_softc *es = &en_softc[unit]; 309 register struct endevice *addr = (struct endevice *)ui->ui_addr; 310 311 if (es->es_oactive == 0) 312 return; 313 if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 314 es->es_if.if_oerrors++; 315 endocoll(unit); 316 return; 317 } 318 es->es_if.if_opackets++; 319 es->es_oactive = 0; 320 es->es_delay = 0; 321 es->es_mask = ~0; 322 if (es->es_ifuba.ifu_xtofree) { 323 m_freem(es->es_ifuba.ifu_xtofree); 324 es->es_ifuba.ifu_xtofree = 0; 325 } 326 if (es->es_if.if_snd.ifq_head == 0) { 327 es->es_lastx = 256; /* putatively illegal */ 328 return; 329 } 330 enstart(unit); 331 } 332 333 /* 334 * Collision on ethernet interface. Do exponential 335 * backoff, and retransmit. If have backed off all 336 * the way print warning diagnostic, and drop packet. 337 */ 338 encollide(unit) 339 int unit; 340 { 341 struct en_softc *es = &en_softc[unit]; 342 343 es->es_if.if_collisions++; 344 if (es->es_oactive == 0) 345 return; 346 endocoll(unit); 347 } 348 349 endocoll(unit) 350 int unit; 351 { 352 register struct en_softc *es = &en_softc[unit]; 353 354 /* 355 * Es_mask is a 16 bit number with n low zero bits, with 356 * n the number of backoffs. When es_mask is 0 we have 357 * backed off 16 times, and give up. 358 */ 359 if (es->es_mask == 0) { 360 printf("en%d: send error\n", unit); 361 enxint(unit); 362 return; 363 } 364 /* 365 * Another backoff. Restart with delay based on n low bits 366 * of the interval timer. 367 */ 368 es->es_mask <<= 1; 369 es->es_delay = mfpr(ICR) &~ es->es_mask; 370 enstart(unit); 371 } 372 373 #ifdef notdef 374 struct sockproto enproto = { AF_ETHERLINK }; 375 struct sockaddr_en endst = { AF_ETHERLINK }; 376 struct sockaddr_en ensrc = { AF_ETHERLINK }; 377 #endif 378 /* 379 * Ethernet interface receiver interrupt. 380 * If input error just drop packet. 381 * Otherwise purge input buffered data path and examine 382 * packet to determine type. If can't determine length 383 * from type, then have to drop packet. Othewise decapsulate 384 * packet based on type and pass to type specific higher-level 385 * input routine. 386 */ 387 enrint(unit) 388 int unit; 389 { 390 register struct en_softc *es = &en_softc[unit]; 391 struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 392 register struct en_header *en; 393 struct mbuf *m; 394 int len; short resid; 395 register struct ifqueue *inq; 396 int off, s; 397 398 es->es_if.if_ipackets++; 399 400 /* 401 * Purge BDP; drop if input error indicated. 402 */ 403 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 404 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 405 if (addr->en_istat&EN_IERROR) { 406 es->es_if.if_ierrors++; 407 goto setup; 408 } 409 410 /* 411 * Calculate input data length. 412 * Get pointer to ethernet header (in input buffer). 413 * Deal with trailer protocol: if type is PUP trailer 414 * get true type from first 16-bit word past data. 415 * Remember that type was trailer by setting off. 416 */ 417 resid = addr->en_iwc; 418 if (resid) 419 resid |= 0176000; 420 len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 421 len -= sizeof (struct en_header); 422 if (len > ENMRU) 423 goto setup; /* sanity */ 424 en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 425 en->en_type = ntohs(en->en_type); 426 #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 427 if (en->en_type >= ENTYPE_TRAIL && 428 en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 429 off = (en->en_type - ENTYPE_TRAIL) * 512; 430 if (off > ENMTU) 431 goto setup; /* sanity */ 432 en->en_type = ntohs(*endataaddr(en, off, u_short *)); 433 resid = ntohs(*(endataaddr(en, off+2, u_short *))); 434 if (off + resid > len) 435 goto setup; /* sanity */ 436 len = off + resid; 437 } else 438 off = 0; 439 if (len == 0) 440 goto setup; 441 #ifdef ENF_SWABIPS 442 if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 443 enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 444 #endif 445 /* 446 * Pull packet off interface. Off is nonzero if packet 447 * has trailing header; if_rubaget will then force this header 448 * information to be at the front, but we still have to drop 449 * the type and length which are at the front of any trailer data. 450 */ 451 m = if_rubaget(&es->es_ifuba, len, off, &es->es_if); 452 if (m == 0) 453 goto setup; 454 if (off) { 455 struct ifnet *ifp; 456 457 ifp = *(mtod(m, struct ifnet **)); 458 m->m_off += 2 * sizeof (u_short); 459 m->m_len -= 2 * sizeof (u_short); 460 *(mtod(m, struct ifnet **)) = ifp; 461 } 462 switch (en->en_type) { 463 464 #ifdef INET 465 case ENTYPE_IP: 466 schednetisr(NETISR_IP); 467 inq = &ipintrq; 468 break; 469 #endif 470 #ifdef PUP 471 case ENTYPE_PUP: 472 rpup_input(m); 473 goto setup; 474 #endif 475 #ifdef NS 476 case ETHERTYPE_NS: 477 if (es->es_nsactive) { 478 schednetisr(NETISR_NS); 479 inq = &nsintrq; 480 } else { 481 m_freem(m); 482 goto setup; 483 } 484 break; 485 #endif 486 487 default: 488 #ifdef notdef 489 enproto.sp_protocol = en->en_type; 490 endst.sen_host = en->en_dhost; 491 endst.sen_net = ensrc.sen_net = es->es_if.if_net; 492 ensrc.sen_host = en->en_shost; 493 raw_input(m, &enproto, 494 (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 495 #else 496 m_freem(m); 497 #endif 498 goto setup; 499 } 500 501 s = splimp(); 502 if (IF_QFULL(inq)) { 503 IF_DROP(inq); 504 m_freem(m); 505 } else 506 IF_ENQUEUE(inq, m); 507 splx(s); 508 509 setup: 510 /* 511 * Reset for next packet. 512 */ 513 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 514 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 515 addr->en_istat = EN_IEN|EN_GO; 516 } 517 518 /* 519 * Ethernet output routine. 520 * Encapsulate a packet of type family for the local net. 521 * Use trailer local net encapsulation if enough data in first 522 * packet leaves a multiple of 512 bytes of data in remainder. 523 */ 524 enoutput(ifp, m0, dst) 525 struct ifnet *ifp; 526 struct mbuf *m0; 527 struct sockaddr *dst; 528 { 529 int type, dest, s, error; 530 register struct mbuf *m = m0; 531 register struct en_header *en; 532 register int off; 533 534 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 535 error = ENETDOWN; 536 goto bad; 537 } 538 switch (dst->sa_family) { 539 540 #ifdef INET 541 case AF_INET: 542 { 543 struct in_addr in; 544 545 in = ((struct sockaddr_in *)dst)->sin_addr; 546 if (in_broadcast(in)) 547 dest = EN_BROADCAST; 548 else 549 dest = in_lnaof(in); 550 } 551 if (dest >= 0x100) { 552 error = EPERM; /* ??? */ 553 goto bad; 554 } 555 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 556 /* need per host negotiation */ 557 if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 558 if (off > 0 && (off & 0x1ff) == 0 && 559 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 560 type = ENTYPE_TRAIL + (off>>9); 561 m->m_off -= 2 * sizeof (u_short); 562 m->m_len += 2 * sizeof (u_short); 563 *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 564 *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 565 goto gottrailertype; 566 } 567 type = ENTYPE_IP; 568 off = 0; 569 goto gottype; 570 #endif 571 #ifdef NS 572 case AF_NS: 573 { 574 u_char *up; 575 576 type = ETHERTYPE_NS; 577 up = ((struct sockaddr_ns *)dst)->sns_addr.x_host.c_host; 578 if (*up & 1) 579 dest = EN_BROADCAST; 580 else 581 dest = up[5]; 582 583 off = 0; 584 goto gottype; 585 } 586 #endif 587 #ifdef PUP 588 case AF_PUP: 589 dest = ((struct sockaddr_pup *)dst)->spup_host; 590 type = ENTYPE_PUP; 591 off = 0; 592 goto gottype; 593 #endif 594 595 #ifdef notdef 596 case AF_ETHERLINK: 597 goto gotheader; 598 #endif 599 600 default: 601 printf("en%d: can't handle af%d\n", ifp->if_unit, 602 dst->sa_family); 603 error = EAFNOSUPPORT; 604 goto bad; 605 } 606 607 gottrailertype: 608 /* 609 * Packet to be sent as trailer: move first packet 610 * (control information) to end of chain. 611 */ 612 while (m->m_next) 613 m = m->m_next; 614 m->m_next = m0; 615 m = m0->m_next; 616 m0->m_next = 0; 617 m0 = m; 618 619 gottype: 620 /* 621 * Add local net header. If no space in first mbuf, 622 * allocate another. 623 */ 624 if (m->m_off > MMAXOFF || 625 MMINOFF + sizeof (struct en_header) > m->m_off) { 626 MGET(m, M_DONTWAIT, MT_HEADER); 627 if (m == 0) { 628 error = ENOBUFS; 629 goto bad; 630 } 631 m->m_next = m0; 632 m->m_off = MMINOFF; 633 m->m_len = sizeof (struct en_header); 634 } else { 635 m->m_off -= sizeof (struct en_header); 636 m->m_len += sizeof (struct en_header); 637 } 638 en = mtod(m, struct en_header *); 639 /* add en_shost later */ 640 en->en_dhost = dest; 641 en->en_type = htons((u_short)type); 642 643 #ifdef notdef 644 gotheader: 645 #endif 646 /* 647 * Queue message on interface, and start output if interface 648 * not yet active. 649 */ 650 s = splimp(); 651 if (IF_QFULL(&ifp->if_snd)) { 652 IF_DROP(&ifp->if_snd); 653 error = ENOBUFS; 654 goto qfull; 655 } 656 IF_ENQUEUE(&ifp->if_snd, m); 657 if (en_softc[ifp->if_unit].es_oactive == 0) 658 enstart(ifp->if_unit); 659 splx(s); 660 return (0); 661 qfull: 662 m0 = m; 663 splx(s); 664 bad: 665 m_freem(m0); 666 return (error); 667 } 668 669 /* 670 * Process an ioctl request. 671 */ 672 enioctl(ifp, cmd, data) 673 register struct ifnet *ifp; 674 int cmd; 675 caddr_t data; 676 { 677 register struct en_softc *es = ((struct en_softc *)ifp); 678 struct ifaddr *ifa = (struct ifaddr *) data; 679 int s = splimp(), error = 0; 680 struct endevice *enaddr; 681 682 switch (cmd) { 683 684 case SIOCSIFADDR: 685 enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 686 es->es_host = (~enaddr->en_addr) & 0xff; 687 /* 688 * Attempt to check agreement of protocol address 689 * and board address. 690 */ 691 switch (ifa->ifa_addr.sa_family) { 692 case AF_INET: 693 if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) 694 return (EADDRNOTAVAIL); 695 break; 696 #ifdef NS 697 case AF_NS: 698 if (IA_SNS(ifa)->sns_addr.x_host.c_host[5] 699 != es->es_host) 700 return (EADDRNOTAVAIL); 701 es->es_nsactive = 1; 702 break; 703 #endif 704 } 705 ifp->if_flags |= IFF_UP; 706 if ((ifp->if_flags & IFF_RUNNING) == 0) 707 eninit(ifp->if_unit); 708 break; 709 710 default: 711 error = EINVAL; 712 break; 713 } 714 splx(s); 715 return (error); 716 } 717 718 #ifdef ENF_SWABIPS 719 /* 720 * Swab bytes 721 * Jeffrey Mogul, Stanford 722 */ 723 enswab(from, to, n) 724 register unsigned char *from, *to; 725 register int n; 726 { 727 register unsigned long temp; 728 729 if ((n <= 0) || (n > 0xFFFF)) { 730 printf("enswab: bad len %d\n", n); 731 return; 732 } 733 734 n >>= 1; n++; 735 #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} 736 /* round to multiple of 8 */ 737 while ((--n) & 07) 738 STEP; 739 n >>= 3; 740 while (--n >= 0) { 741 STEP; STEP; STEP; STEP; 742 STEP; STEP; STEP; STEP; 743 } 744 } 745 #endif 746 #endif 747