📄 ip_output.c
字号:
if (so){ smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; } } } if (error) break; else { /* bump up counters for network management */ IPSTAT(ips_totalsent++); /* a packet was successfully fragmented */ if(ip->ip_off & IP_MF) { IPSTAT(ips_outpktsfrag++); } } }bad: m_freem(m); m = NULL;done: RTLOCK(); if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) rtfree(ro->ro_rt); RTUNLOCK(); return (error);}/* * Insert IP options into preformed packet. * Adjust IP destination as required for IP source routing, * as indicated by a non-zero in_addr at the start of the options. */struct mbuf *ip_insertoptions(m, opt, phlen) register struct mbuf *m; struct mbuf *opt; int *phlen;{ register struct ipoption *p = mtod(opt, struct ipoption *); struct mbuf *n; register struct ip *ip = mtod(m, struct ip *); unsigned optlen; optlen = opt->m_len - sizeof(p->ipopt_dst);#ifdef mips while(optlen&0x03) /* word align options, if necessary */ optlen++;#endif mips if (p->ipopt_dst.s_addr) ip->ip_dst = p->ipopt_dst; if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { MGET(n, M_DONTWAIT, MT_DATA); if (n == 0) return (m); m->m_len -= sizeof(struct ip); m->m_off += sizeof(struct ip); n->m_next = m; m = n; m->m_off = MMAXOFF - sizeof(struct ip) - optlen; m->m_len = optlen + sizeof(struct ip); bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); } else { m->m_off -= optlen; m->m_len += optlen; ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); } ip = mtod(m, struct ip *); bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); *phlen = sizeof(struct ip) + optlen; ip->ip_len += optlen; return (m);}/* * Copy options from ip to jp. * If off is 0 all options are copied * otherwise copy selectively. */ip_optcopy(ip, jp, off) struct ip *ip, *jp; int off;{ register u_char *cp, *dp; int opt, optlen, cnt; cp = (u_char *)(ip + 1); dp = (u_char *)(jp + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else optlen = cp[IPOPT_OLEN]; if (optlen > cnt) /* XXX */ optlen = cnt; /* XXX */ if (off == 0 || IPOPT_COPIED(opt)) { bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); dp += optlen; } } for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) *dp++ = IPOPT_EOL; return (optlen);}/* * IP socket option processing. */ip_ctloutput(op, so, level, optname, m) int op; struct socket *so; int level, optname; struct mbuf **m;{ int error = 0; struct inpcb *inp = sotoinpcb(so); if (level != IPPROTO_IP) error = EINVAL; else switch (op) { case PRCO_SETOPT: switch (optname) { case IP_OPTIONS: return (ip_pcbopts(&inp->inp_options, *m)); default: error = EINVAL; break; } break; case PRCO_GETOPT: switch (optname) { case IP_OPTIONS: *m = m_get(M_DONTWAIT, MT_SOOPTS); if (*m == NULL){ error = ENOBUFS; break; } if (inp->inp_options) { (*m)->m_off = inp->inp_options->m_off; (*m)->m_len = inp->inp_options->m_len; bcopy(mtod(inp->inp_options, caddr_t), mtod(*m, caddr_t), (unsigned)(*m)->m_len); } else (*m)->m_len = 0; break; default: error = EINVAL; break; } break; } if (op == PRCO_SETOPT && *m) (void)m_free(*m); return (error);}/* * Set up IP options in pcb for insertion in output packets. * Store in mbuf with pointer in pcbopt, adding pseudo-option * with destination address if source routed. */ip_pcbopts(pcbopt, m) struct mbuf **pcbopt; register struct mbuf *m;{ register int cnt, optlen; register u_char *cp; u_char opt; /* turn off any old options */ if (*pcbopt) (void)m_free(*pcbopt); *pcbopt = 0; if (m == (struct mbuf *)0 || m->m_len == 0) { /* * Only turning off any previous options. */ if (m) (void)m_free(m); return (0); } if (m->m_len % sizeof(long)) goto bad; /* * IP first-hop destination address will be stored before * actual options; move other options back * and clear it when none present. */#if MAX_IPOPTLEN >= MMAXOFF - MMINOFF if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) goto bad;#else if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) goto bad;#endif cnt = m->m_len; m->m_len += sizeof(struct in_addr); cp = mtod(m, u_char *) + sizeof(struct in_addr); ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); bzero(mtod(m, caddr_t), sizeof(struct in_addr)); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= IPOPT_OLEN || optlen > cnt) goto bad; } switch (opt) { default: break; case IPOPT_LSRR: case IPOPT_SSRR: /* * user process specifies route as: * ->A->B->C->D * D must be our final destination (but we can't * check that since we may not have connected yet). * A is first hop destination, which doesn't appear in * actual IP option, but is stored before the options. */ if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) goto bad; m->m_len -= sizeof(struct in_addr); cnt -= sizeof(struct in_addr); optlen -= sizeof(struct in_addr); cp[IPOPT_OLEN] = optlen; /* * Move first hop before start of options. */ bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), sizeof(struct in_addr)); /* * Then copy rest of options back * to close up the deleted entry. */ ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)), (caddr_t)&cp[IPOPT_OFFSET+1], (unsigned)cnt + sizeof(struct in_addr)); break; } } *pcbopt = m; return (0);bad: (void)m_free(m); return (EINVAL);}/* * Attempt to fragment type 2 mbuf chain. * Works only if each mbuf is smaller than a packet. * This saves copying all the data. */ip_frag2(m, ip, maxpacketlen, errorp, ifp, dst, so) register struct mbuf *m; register struct ip *ip; register int maxpacketlen; int *errorp; struct ifnet *ifp; struct sockaddr *dst; struct socket *so;{ struct mbuf *mm; struct mbuf *lastm; register struct mbuf *mh; register int fraglen, fragoff, pktlen, n; struct ip *nextip; int saveaffinity; /* * Check whether we can do it. */ mm = m; n = 0; while (m) { if (m->m_off > MMAXOFF && m->m_cltype == 2) { n++; } if (m->m_len + sizeof (struct ip) > maxpacketlen) { return (0); } m = m->m_next; } if (n == 0) { /* higher level does type 1 chain better */ return (0); } m = mm; fragoff = 0; while (m) { pktlen = 0; mm = m; /* * Gather up all the mbufs that will fit in a frag. */ while (m && pktlen + m->m_len <= maxpacketlen) { pktlen += m->m_len; lastm = m; m = m->m_next; } fraglen = pktlen - sizeof (struct ip); lastm->m_next = 0; if (m) { /* * There are more frags, so we prepend * a copy of the ip hdr to the rest * of the chain. */ MGET(mh, M_DONTWAIT, MT_DATA); if (mh == 0) { *errorp = ENOBUFS; IPSTAT(ips_outdiscard++); /* a packet was * discarded */ break; } mh->m_off = MMAXOFF - sizeof (struct ip) - 8; nextip = mtod(mh, struct ip *); /* copy the ip header */ *nextip = *ip; mh->m_len = sizeof (struct ip); mh->m_next = m; m = mh; if (n = (fraglen & 7)) { /* * IP fragments must be a multiple of * 8 bytes long so we must play games. */ bcopy(mtod(lastm, caddr_t) + lastm->m_len - n, (caddr_t) (nextip + 1), n); lastm->m_len -= n; mh->m_len += n; pktlen -= n; fraglen -= n; } ip->ip_off = htons((u_short) ((fragoff >> 3) | IP_MF)); } else { ip->ip_off = htons((u_short) (fragoff >> 3)); } /* * Fix up the ip header for the mm chain and send it off. */ if (ip->ip_len < pktlen) { ip->ip_len = htons((u_short) ip->ip_len); if (m) { m_freem(m); m = 0; } } else { ip->ip_len = htons((u_short) pktlen); if (m) { nextip->ip_len -= fraglen; } } ip->ip_sum = 0; ip->ip_sum = in_cksum(mm, sizeof (struct ip)); /* Support for nonsymm net devices. 8.9.88.us */ if (!smp) *errorp = (*ifp->if_output)(ifp, mm, dst); else{ if (ifp->d_affinity != boot_cpu_mask) *errorp = (*ifp->if_output)(ifp, mm, dst); else{ if (so){ so->ref = 26; smp_unlock(&so->lk_socket); } CALL_TO_NONSMP_DRIVER( (*ifp), saveaffinity); *errorp = (*ifp->if_output)(ifp, mm, dst); RETURN_FROM_NONSMP_DRIVER( (*ifp), saveaffinity); if (so){ smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; } } } if (*errorp){ if(m) m_freem(m); break; } else { IPSTAT(ips_totalsent++); /* fragmentation was successfull */ IPSTAT(ips_outtotalfrag++); } ip = nextip; fragoff += fraglen; } return (1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -