📄 if_un.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_un.c 4.1 ULTRIX 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * 13-Jun-86 -- jaw fix to uba reset and drivers. * * * 18-mar-86 -- jaw br/cvec changed to NOT use registers. * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************/#include "un.h"#if NUN > 0 || defined(BINARY)/* * Ungermann-Bass network/DR11-W interface driver */#include "../data/if_un_data.c"#define UNMTU (600-sizeof (struct un_header))#define US_NULL 0 /* not doing anything state */#define US_IDLE 1 /* waiting to transfer state */#define US_READ 2 /* reading state */#define US_WRITE 3 /* writing state */#define US_RESET 4 /* waiting for reset state */int unprobe(), unattach(), unintr();u_short unstd[] = { 0 };struct uba_driver undriver = { unprobe, 0, unattach, 0, unstd, "un", uninfo };#define UNUNIT(dev) (minor(dev))int uninit(), unioctl(), unoutput(), unreset();int unrestart();/* * Cause an interrupt to determine interface presence and * interrupt vector. */unprobe(reg) caddr_t reg;{ register struct undevice *addr = (struct undevice *)reg;#ifdef lint unintr(0);#endif addr->csr = IE|UNRESET; addr->csr = IE|UNRESET|GO; DELAY(100000); addr->csr = 0; return (1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */unattach(ui) struct uba_device *ui;{ register struct un_softc *us = &un_softc[ui->ui_unit]; us->us_if.if_unit = ui->ui_unit; us->us_if.if_name = "un"; us->us_if.if_mtu = UNMTU; us->us_if.if_init = uninit; us->us_if.if_ioctl = unioctl; us->us_if.if_output = unoutput; us->us_if.if_reset = unreset; us->us_if.if_watchdog = unrestart; us->us_maxtime = 3; us->us_maxerr = 10; us->us_restart = 5 * 60; us->us_ifuba.ifu_flags = UBA_CANTWAIT;#ifdef notdef us->us_ifuba.ifu_flags |= UBA_NEEDBDP;#endif if_attach(&us->us_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */unreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= nNUN || (ui = uninfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" un%d", unit); uninit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */uninit(unit) int unit;{ register struct un_softc *us = &un_softc[unit]; register struct uba_device *ui = uninfo[unit]; register struct undevice *addr; struct sockaddr_in *sin; int s; sin = (struct sockaddr_in *)&us->us_if.if_addr; if (in_netof(sin->sin_addr) == 0) return; if (if_ubainit(&us->us_ifuba, ui->ui_ubanum, sizeof (struct un_header), (int)btoc(UNMTU)) == 0) { printf("un%d: can't initialize\n", unit); us->us_if.if_flags &= ~IFF_UP; return; } us->us_if.if_flags |= IFF_RUNNING; us->us_errcnt = 0; us->us_errtime = time.tv_sec; unwhoami(unit); /* * Reset U-B interface, thus causing an interrupt which * will start things going. */ addr = (struct undevice *)ui->ui_addr; s = splimp(); addr->csr = IE|UNRESET; addr->csr = IE|UNRESET|GO; us->us_state = US_RESET; splx(s);}/* * Try to start a write operation. * If interface is busy, it must be in idle state, so issue a reset. * Otherwise, get the datagram from the output queue, map it onto * the UNIBUS, and start the write. This routine should not be * called if the output queue is empty. */unstart(dev) dev_t dev;{ int unit = UNUNIT(dev); struct uba_device *ui = uninfo[unit]; register struct un_softc *us = &un_softc[unit]; register struct undevice *addr = (struct undevice *)ui->ui_addr; struct mbuf *m; int dataaddr, datalen; register short cmdcsr; if (us->us_state != US_NULL) { addr->csr = IE|UNRESET; addr->csr = IE|UNRESET|GO; us->us_state = US_RESET; } else { IF_DEQUEUE(&us->us_if.if_snd, m); if (m == 0) return; us->us_state = US_WRITE; datalen = if_wubaput(&us->us_ifuba, m); if (us->us_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(us->us_ifuba.ifu_uba, us->us_ifuba.ifu_w.ifrw_bdp, us->us_ifuba.ifu_uban); dataaddr = us->us_ifuba.ifu_w.ifrw_info; addr->bar = dataaddr & 0xffff; addr->wcr = -(((datalen + 1) >> 1) + 1); cmdcsr = ((dataaddr >> 12) & 0x30) | IE | UNOUT; addr->csr = cmdcsr; addr->csr = cmdcsr | GO; }}/* * Ungermann-Bass interface interrupt handler. * Determines reason for interrupt and acts accordingly. */unintr(unit) int unit;{ register struct un_softc *us = &un_softc[unit]; struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; register struct un_header *un; struct mbuf *m; int len; register struct ifqueue *inq; int cmdcsr; if ((addr->dar & RESETACK) && us->us_state != US_RESET) { if ((us->us_if.if_flags & IFF_UP) == 0) return; printf("un%d: unexpected reset\n", unit); unerror(unit); } switch (us->us_state) { case US_NULL: printf("un%d: stray interrupt\n", unit); break; case US_RESET: if (!(addr->dar & RESETACK)) { addr->csr = IE|UNRESET; addr->csr = IE|UNRESET|GO; return; } break; case US_IDLE: break; case US_READ: us->us_if.if_ipackets++; if (us->us_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(us->us_ifuba.ifu_uba, us->us_ifuba.ifu_r.ifrw_bdp, us->us_ifuba.ifu_uban); if (addr->csr & STATA) { if ((us->us_if.if_flags & IFF_UP) == 0) return; printf("un%d: input error csr=%b\n", unit, addr->csr&0xffff, UNBITS); us->us_if.if_ierrors++; unerror(unit); break; } un = (struct un_header *)(us->us_ifuba.ifu_r.ifrw_addr); switch (un->un_ptype) {#ifdef INET case UNTYPE_IP: len = htons((u_short)((struct ip *) (un+1))->ip_len); schednetisr(NETISR_IP); inq = &ipintrq; break;#endif case UNTYPE_INQUIRE: { struct sockaddr_in *sin;#ifdef ultrix1.1 /* obviously this driver does not work anymore */ us->us_if.if_host[0] = un->un_dport << 16 | htons(un->un_dniu); sin = (struct sockaddr_in *)&us->us_if.if_addr; sin->sin_addr = if_makeaddr(us->us_if.if_net, us->us_if.if_host[0]); us->us_if.if_flags |= IFF_UP; if_rtinit(&us->us_if, RTF_UP);#endif goto setup; } default: printf("un%d: bad packet type %d\n", un->un_ptype); goto setup; } m = if_rubaget(&us->us_ifuba, len, 0); if (m != 0) if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); break; case US_WRITE: us->us_if.if_opackets++; if (addr->csr & STATA) { if ((us->us_if.if_flags & IFF_UP) == 0) return; printf("un%d: output error csr=%b\n", unit, addr->csr, UNBITS); us->us_if.if_oerrors++; unerror(unit); } if (us->us_ifuba.ifu_xtofree) { m_freem(us->us_ifuba.ifu_xtofree); us->us_ifuba.ifu_xtofree = 0; } break; default: printf("un%d: invalid state %d csr=%b\n", us->us_state, addr->csr, UNBITS); }setup: us->us_state = US_NULL; if (addr->csr & STATB) { us->us_state = US_READ; addr->wcr = -((sizeof (struct un_header) + UNMTU + 1)/2+1); addr->bar = us->us_ifuba.ifu_r.ifrw_info & 0xffff; cmdcsr = ((us->us_ifuba.ifu_r.ifrw_info >> 12) & 0x30); cmdcsr |= IE|UNRDDG; addr->csr = cmdcsr; addr->csr = cmdcsr | GO; } else if (us->us_if.if_snd.ifq_head != 0 && (addr->csr & STATC)) unstart(unit); if (us->us_state == US_NULL) { us->us_state = US_IDLE; addr->csr = IE|UNIDLE; addr->csr = IE|UNIDLE|GO; }}/* * Ungermann-Bass output routine. * Encapsulate a packet destined for dst for the local net. */unoutput(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ int type, destniu, destport, len; register struct mbuf *m = m0; register struct un_header *un; register struct un_softc *us = &un_softc[ifp->if_unit]; int s; if ((us->us_if.if_flags & IFF_UP) == 0) return (ENETDOWN); switch (dst->sa_family) {#ifdef INET case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)dst; struct ip *ip = mtod(m, struct ip *); if (sin->sin_addr.s_addr & 0xffffff00) { destniu = sin->sin_addr.s_addr >> 24; destport = (sin->sin_addr.s_addr >> 8) & 0xff; } else { destniu = 0xffff; destport = 0xff; } len = htons((u_short) ip->ip_len); type = UNTYPE_IP; break; }#endif default: printf("un%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); m_freem(m0); return (EAFNOSUPPORT); } /* * Add local net header. If no space in first mbuf, * allocate another. */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct un_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(m0); return (ENOBUFS); } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct un_header); } else { m->m_off -= sizeof (struct un_header); m->m_len += sizeof (struct un_header); } un = mtod(m, struct un_header *); bzero((caddr_t)un, sizeof (struct un_header)); un->un_length = htons((u_short)(len + sizeof (struct un_header))); un->un_dniu = htons((u_short)destniu); un->un_dport = destport; un->un_dtype = 5;#ifdef ultrix1.1 un->un_sniu = htons((u_short)(ifp->if_host[0] >> 24)); un->un_sport = (ifp->if_host[0] >> 8) & 0xff;#endif un->un_stype = 5; un->un_ptype = type; /* * Queue message on interface, and start output if interface * not yet active. */ s = splimp(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); if (us->us_state == US_IDLE) unstart(ifp->if_unit); splx(s); return (0);}/* * U-B error handler, if maxerr errors have occured * in maxtime seconds, disable the interface. */unerror(unit) int unit;{ register struct un_softc *us = &un_softc[unit]; struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; if (time.tv_sec - us->us_errtime > us->us_maxtime) { us->us_errtime = time.tv_sec; us->us_errcnt = 1; } else if (++us->us_errcnt >= us->us_maxerr) { printf("un%d: error limit exceeded\n", unit); us->us_if.if_flags &= ~IFF_UP; addr->csr = 0; us->us_if.if_timer = us->us_restart; }}unrestart(unit) int unit;{ register struct un_softc *us = &un_softc[unit]; struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; int s; us->us_if.if_flags |= IFF_UP; printf("un%d: restarting\n", unit); unwhoami(unit); s = splimp(); addr->csr = IE|UNRESET; addr->csr = IE|UNRESET|GO; us->us_state = US_RESET; splx(s);}/* * Send a "Who am I?" message to the interface. * Interface should respond with an copy of the * packet with its real address filled in. The * message is placed at the head of the output queue. * An interface reset should be done next to start * things rolling. */unwhoami(unit) int unit;{ register struct mbuf *m; register struct un_softc *us = &un_softc[unit]; register struct un_header *un; int s; if ((m = m_get(M_DONTWAIT, MT_DATA)) == 0) return; m->m_off = MMINOFF; m->m_len = sizeof(struct un_header); un = mtod(m, struct un_header *); bzero((caddr_t)un, sizeof (struct un_header)); un->un_length = htons(sizeof (struct un_header)); un->un_dtype = un->un_stype = 5; un->un_ptype = UNTYPE_INQUIRE; s = splimp(); IF_PREPEND(&us->us_if.if_snd, m); splx(s);}/* * Process an ioctl request. */unioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) uninit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -