📄 if_ni.c
字号:
int off, resid; struct ifqueue *inq; /* * Deal with trailer protocol: if type is trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ if (swloop) { eh = mtod(swloop, struct ether_header *); swloop_eh = *eh; eh = &swloop_eh; if ( swloop->m_len > sizeof(struct ether_header)) m_adj(swloop, sizeof(struct ether_header)); else { MFREE(swloop, swloop_tmp1); if ( ! swloop_tmp1 ) return; else swloop = swloop_tmp1; } } else eh = (struct ether_header *)(vaddr(bde)); eh->ether_type = ntohs((u_short)eh->ether_type);#define dataaddr(eh, off, type) ((type)(((caddr_t)(eh)+(off)))) if (eh->ether_type >= ETHERTYPE_TRAIL && eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ if (swloop) { struct mbuf *mprev, *m0 = swloop;/* need to check this against off */ mprev = m0; while (swloop->m_next){/*real header at end of chain*/ mprev = swloop; swloop = swloop->m_next; } /* move to beginning of chain */ mprev->m_next = 0; swloop->m_next = m0; eh->ether_type = ntohs( *mtod(swloop, u_short *)); } else { struct ether_header *peh; peh = (struct ether_header *)vaddr(bde+1); eh->ether_type = ntohs(*dataaddr(peh, off, u_short *)); resid = ntohs(*(dataaddr(peh, off+2, u_short *))); if (off + resid > len) return; /* sanity */ } } else off = 0; if (len == 0) return; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; niget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ if (swloop) { m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); } else { /* Header was in the 1st buffer */ bde++; /* * subtract the ethernet header AND checksum field length */ len -= sizeof(struct ether_header)+4; m = niget(ni, bde, len, off); } if (m == 0) return; if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } /* Dispatch this packet */ net_read(&(ds->ds_ed), eh, m, len, (swloop != NULL), (off != 0));}/* * Process an ioctl request. */niioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ni_softc *ds = &ni_softc[ifp->if_unit]; register struct ni *ni = &niinfo[ifp->if_unit]; register struct nidevice *addr = (struct nidevice *)ni->ni_regs; struct protosw *pr; struct ifreq *ifr = (struct ifreq *)data; struct ifdevea *ifd = (struct ifdevea *)data; register struct ifaddr *ifa = (struct ifaddr *)data; int s,t,z = splnet(), error = 0, empty; switch (cmd) { case SIOCENABLBACK: ifp->if_flags |= IFF_LOOPBACK; break; case SIOCDISABLBACK: ifp->if_flags &= ~IFF_LOOPBACK; niinit(ifp->if_unit); break; case SIOCRPHYSADDR: /* * read default hardware address. */ s = splimp(); smp_lock(&ds->lk_ni_softc, LK_RETRY); bcopy(ds->ds_dpaddr, ifd->default_pa, 6); bcopy(ds->ds_addr, ifd->current_pa, 6); smp_unlock(&ds->lk_ni_softc); splx(s); break; case SIOCSPHYSADDR: /* * Set physaddr. */ niinit(ifp->if_unit); { struct ni_msg *ni_msg; if((ni_msg = (struct ni_msg *)remqhi(&ni->freeq0, NI_MAXITRY))!= (struct ni_msg *)QEMPTY) { ni_msg->opcode = SNDMSG; ni_msg->status = 0; ni_msg->ni_opcode = NIOP_WPARAM; ni_msg->msg_len = sizeof (struct ni_param) + 6; ((struct ni_param *)&ni_msg->text[0])->flags = NI_PAD; bcopy(ifr->ifr_addr.sa_data, ((struct ni_param *)&ni_msg->text[0])->apa, 6); bcopy(ifr->ifr_addr.sa_data, ds->ds_addr, 6);#if NPACKETFILTER > 0 /* tell packet filter about new address */ pfilt_newaddress(ds->ds_ed.ess_enetunit, ds->ds_addr);#endif NPACKETFILTER > 0 if((empty=insqti(ni_msg, &ni->comq0, NI_MAXITRY))>0) printf("insqti failed\n"); else if(empty == QEMPTY) { while((addr->pc&PC_OWN)) ; addr->pc = PC_CMDQNE|PC_CMDQ0|PC_OWN; } } } break; case SIOCDELMULTI: case SIOCADDMULTI: { int i,j = -1; s = splimp(); smp_lock(&ds->lk_ni_softc, LK_RETRY); if (cmd==SIOCDELMULTI) { for (i = 0; i < NMULTI; i++) if (bcmp(ds->ds_multi[i], ifr->ifr_addr.sa_data,MULTISIZE) == 0) { if (--ds->ds_muse[i] == 0) bcopy(ni_multi,ds->ds_multi[i],MULTISIZE); } } else { for (i = 0; i < NMULTI; i++) { if (bcmp(ds->ds_multi[i],ifr->ifr_addr.sa_data,MULTISIZE) == 0) { ds->ds_muse[i]++; smp_unlock(&ds->lk_ni_softc); splx(s); goto done; } if (bcmp(ds->ds_multi[i],ni_multi,MULTISIZE) == 0) j = i; } if (j == -1) { printf("ni%d: multi failed, multicast list full: %d\n", ni->unit, NMULTI); error = ENOBUFS; smp_unlock(&ds->lk_ni_softc); splx(s); goto done; } bcopy(ifr->ifr_addr.sa_data, ds->ds_multi[j], MULTISIZE); ds->ds_muse[j]++; } /* Update up Protocol Type Definition Block */ if(ifp->if_flags&IFF_UP) ni_sptdb(ni,ETHERTYPE_IP,2,2,PTDB_UNK|PTDB_BDC,1); smp_unlock(&ds->lk_ni_softc); splx(s); break; } case SIOCRDCTRS: case SIOCRDZCTRS: { register struct ctrreq *ctr = (struct ctrreq *)data; /* Read/Read-Clear counters */ struct ni_msg *ni_msg; struct ni_counters *ni_counters; int k;#ifdef vax /* * If we're being called on the interrupt stack, we need * to return failure to avoid a sleep panic. */ if (movpsl() & PSL_IS) { error = EINVAL; goto done; }#endif vax#ifdef mips /* * Currently no solution for mips. Need to fix this. */#endif mips ni_msg = (struct ni_msg *)remqhi(&ni->freeq0, NI_MAXITRY); if(ni_msg == (struct ni_msg *)QEMPTY) { error = ENOBUFS; goto done; } ni_msg->opcode = SNDMSG; if(cmd == SIOCRDCTRS) ni_msg->ni_opcode = NIOP_RDCNTR; else ni_msg->ni_opcode = NIOP_RCCNTR; ni_msg->msg_len = sizeof(struct ni_counters) + 6; while((addr->pc&PC_OWN)) ; k=splimp(); if((empty=insqti(ni_msg, &ni->comq0, NI_MAXITRY))>0) printf("insqti failed\n"); else if(empty == QEMPTY) addr->pc = PC_CMDQNE|PC_CMDQ0|PC_OWN; /* Wait for read counters to finish */ sleep((caddr_t)ni_msg, PUSER); splx(k); ni_counters = (struct ni_counters *)&ni_msg->text[0]; bzero(&ctr->ctr_ctrs, sizeof(struct estat)); ctr->ctr_type = CTR_ETHER; ctr->ctr_ether.est_seconds = ni_counters->last_zero; ctr->ctr_ether.est_bytercvd = *(int *)ni_counters->bytes_rec; ctr->ctr_ether.est_bytesent = *(int *)ni_counters->bytes_snt; ctr->ctr_ether.est_mbytercvd = *(int *)ni_counters->mbytes_rec; ctr->ctr_ether.est_blokrcvd = *(int *)ni_counters->frame_rec; ctr->ctr_ether.est_bloksent = *(int *)ni_counters->frame_snt; ctr->ctr_ether.est_mblokrcvd = *(int *)ni_counters->mframe_rec; ctr->ctr_ether.est_deferred = *(int *)ni_counters->fs_def; ctr->ctr_ether.est_single = *(int *)ni_counters->fs_sc; ctr->ctr_ether.est_multiple = *(int *)ni_counters->fs_mc; ctr->ctr_ether.est_sendfail = ni_counters->sfail; ctr->ctr_ether.est_sendfail_bm = ni_counters->sfbm; ctr->ctr_ether.est_collis = ni_counters->ctf; ctr->ctr_ether.est_recvfail = ni_counters->rfail; ctr->ctr_ether.est_recvfail_bm = ni_counters->rfbm; ctr->ctr_ether.est_unrecog = ni_counters->unrec; ctr->ctr_ether.est_overrun = ni_counters->datao; ctr->ctr_ether.est_sysbuf = ni_counters->sbu; ctr->ctr_ether.est_userbuf = ni_counters->ubu; ctr->ctr_ether.est_mbytesent = *(int *)ni_counters->mbytes_snt; ctr->ctr_ether.est_mbloksent = *(int *)ni_counters->mframe_snt; } break; case SIOCSIFADDR: { ifp->if_flags |= IFF_UP; niinit(ifp->if_unit); switch(ifa->ifa_addr.sa_family) {#ifdef INET case AF_INET: t = splimp(); smp_lock(&lk_ifnet, LK_RETRY); ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; smp_unlock(&lk_ifnet); splx(t); /* 1st packet out */ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif default: if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) { error = (*pr->pr_ifioctl)(ifp, cmd, data); } break; } } break;#ifdef IFF_PROMISC /* IFF_ALLMULTI and NPACKETFILTER, as well */ case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { int newptdb = 0; if ((ifp->if_flags & IFF_PROMISC) == IFF_PROMISC) newptdb |= PTDB_PROM; if ((ifp->if_flags & IFF_ALLMULTI) == IFF_ALLMULTI) newptdb |= PTDB_AMC; ni_sptdb(ni,ETHERTYPE_IP,2,2,PTDB_UNK|PTDB_BDC|newptdb,1); } break;#endif IFF_PROMISC default: error = EINVAL; }done: splx(z); return (error);}/* * Pull read data off a interface. * Len is length of data, with local net header stripped. * Off is non-zero if a trailer protocol was used, and * gives the offset of the trailer information. * We copy the trailer information and then all the normal * data into mbufs. */struct mbuf *niget(ni, bde, totlen, trailoff) struct ni *ni; struct _bd *bde; int totlen, trailoff;{ struct mbuf *top, **mp, *m; int off = trailoff, len = 0; /* setup for 1st buffer */ int cp = (int) vaddr(bde); int bdelen = bde->buf_len; top = 0; mp = ⊤ while (totlen > 0) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) goto bad; if (off) { cp = (int) vaddr(bde) + trailoff; bdelen = bde->buf_len; len = totlen - off; } else len = totlen; if (bdelen >= CLBYTES && len >= CLBYTES) { struct mbuf *p; struct pte *cpte, *ppte; int i; char *newdata; if (!claligned(cp)) goto copy; KM_ALLOC(newdata, char *, M_CLUSTERSZ, KM_CLUSTER, KM_NOWAIT); if (newdata == 0) goto nopage; MCLPUT(m, cp); m->m_len = len; bde->pt_addr = svtopte(newdata); bde->offset = (unsigned)newdata&PGOFSET; bde->buf_len = NI_MAXPACKETSZ; goto nocopy; }nopage: m->m_len = MIN(MLEN, len); m->m_len = MIN(m->m_len, bdelen); m->m_off = MMINOFF;copy: bcopy((caddr_t)cp, mtod(m, caddr_t), (unsigned)m->m_len); cp += m->m_len;nocopy: bdelen -= m->m_len; *mp = m; mp = &m->m_next; if (off) { /* sort of an ALGOL-W style for statement... */ off += m->m_len; if (off == totlen) { cp = (int) vaddr(bde); bdelen = bde->buf_len; off = 0; totlen = trailoff; } } else totlen -= m->m_len; } return (top);bad: m_freem(top); return (0);}ni_sptdb(ni, type, index, q, flags, doclear) struct ni *ni; /* Set Protocol Type Definition Block */{ register struct ni_softc *ds = &ni_softc[ni->unit]; struct ni_msg *ni_msg; struct ptdb *ptdb; int empty,i; struct nidevice *addr = (struct nidevice *)ni->ni_regs; int clear = doclear;loop: ni_msg = (struct ni_msg *)remqhi(&ni->freeq0, NI_MAXITRY); if(ni_msg == (struct ni_msg *)QEMPTY) return; bzero(&ni_msg->text[0], sizeof(struct ptdb)); ni_msg->status = 0; if(clear) ni_msg->ni_opcode = NIOP_CLPTDB; else ni_msg->ni_opcode = NIOP_STPTDB; ni_msg->opcode = SNDMSG; ptdb = (struct ptdb *)&ni_msg->text[0]; ptdb->flags = flags; ptdb->fq_index = q; ptdb->ptt = type; ptdb->ptdb_index = index; ptdb->adr_len = 0; ni_msg->msg_len = 18; if(!clear && flags&(PTDB_AMC|PTDB_BDC)) { int nptdb=0; /* 1st reserved for -1 broadcast addr */ ptdb->adr_len++; ni_msg->msg_len += 8; bcopy(ni_multi, (&ptdb->multi[nptdb++])->addr,6); for (i = 0; i < NMULTI - 1; i++) if (ds->ds_muse[i] > 0) { ptdb->adr_len++; ni_msg->msg_len += 8; bcopy(ds->ds_multi[i],(&ptdb->multi[nptdb++])->addr,6); } } if((empty=insqti(ni_msg, &ni->comq0, NI_MAXITRY)) > 0) printf("insqti failed\n"); else if(empty == QEMPTY) { while((addr->pc&PC_OWN)) ; addr->pc = PC_CMDQNE|PC_CMDQ0|PC_OWN; while((addr->pc&PC_OWN)) ; } else while((addr->pc&PC_OWN)) ; if(clear) { clear = 0; goto loop; }} #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -