📄 ip_output.c
字号:
break; case IP_TOS: case IP_TTL: case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); switch (optname) { case IP_TOS: optval = inp->inp_ip.ip_tos; break; case IP_TTL: optval = inp->inp_ip.ip_ttl; break;#define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) case IP_RECVOPTS: optval = OPTBIT(INP_RECVOPTS); break; case IP_RECVRETOPTS: optval = OPTBIT(INP_RECVRETOPTS); break; case IP_RECVDSTADDR: optval = OPTBIT(INP_RECVDSTADDR); break; } *mtod(m, int *) = optval; break; case IP_MULTICAST_IF: case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP:#ifdef NOTUSED_BY_PMON error = ip_getmoptions(optname, inp->inp_moptions, mp);#else error = EINVAL;#endif break; case IP_PORTRANGE: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); if (inp->inp_flags & INP_HIGHPORT) optval = IP_PORTRANGE_HIGH; else if (inp->inp_flags & INP_LOWPORT) optval = IP_PORTRANGE_LOW; else optval = 0; *mtod(m, int *) = optval; break; case IPSEC_OUTSA:#ifndef IPSEC error = EINVAL;#else s = spltdb(); if (inp->inp_tdb == NULL) { error = ENOENT; } else { tdbi.spi = inp->inp_tdb->tdb_spi; tdbi.dst = inp->inp_tdb->tdb_dst; tdbi.proto = inp->inp_tdb->tdb_sproto; *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(tdbi); bcopy((caddr_t)&tdbi, mtod(m, caddr_t), (unsigned)m->m_len); } splx(s);#endif /* IPSEC */ break; case IP_AUTH_LEVEL: case IP_ESP_TRANS_LEVEL: case IP_ESP_NETWORK_LEVEL:#ifndef IPSEC *mtod(m, int *) = IPSEC_LEVEL_NONE;#else switch (optname) { case IP_AUTH_LEVEL: optval = inp->inp_seclevel[SL_AUTH]; break; case IP_ESP_TRANS_LEVEL: optval = inp->inp_seclevel[SL_ESP_TRANS]; break; case IP_ESP_NETWORK_LEVEL: optval = inp->inp_seclevel[SL_ESP_NETWORK]; break; } *mtod(m, int *) = optval;#endif break; default: error = ENOPROTOOPT; break; } break; } 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. */int#ifdef notyetip_pcbopts(optname, pcbopt, m) int optname;#elseip_pcbopts(pcbopt, m)#endif 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); }#ifndef vax if (m->m_len % sizeof(int32_t)) goto bad;#endif /* * IP first-hop destination address will be stored before * actual options; move other options back * and clear it when none present. */ if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) goto bad; 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; } } if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) goto bad; *pcbopt = m; return (0);bad: (void)m_free(m); return (EINVAL);}#ifdef NOTUSED_BY_PMON/* * Set the IP multicast options in response to user setsockopt(). */intip_setmoptions(optname, imop, m) int optname; struct ip_moptions **imop; struct mbuf *m;{ register int error = 0; u_char loop; register int i; struct in_addr addr; register struct ip_mreq *mreq; register struct ifnet *ifp; register struct ip_moptions *imo = *imop; struct route ro; register struct sockaddr_in *dst; if (imo == NULL) { /* * No multicast option buffer attached to the pcb; * allocate one and initialize to default values. */ imo = (struct ip_moptions *)malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); if (imo == NULL) return (ENOBUFS); *imop = imo; imo->imo_multicast_ifp = NULL; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; imo->imo_num_memberships = 0; } switch (optname) { case IP_MULTICAST_IF: /* * Select the interface for outgoing multicast packets. */ if (m == NULL || m->m_len != sizeof(struct in_addr)) { error = EINVAL; break; } addr = *(mtod(m, struct in_addr *)); /* * INADDR_ANY is used to remove a previous selection. * When no interface is selected, a default one is * chosen every time a multicast packet is sent. */ if (addr.s_addr == INADDR_ANY) { imo->imo_multicast_ifp = NULL; break; } /* * The selected interface is identified by its local * IP address. Find the interface and confirm that * it supports multicasting. */ INADDR_TO_IFP(addr, ifp); if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; } imo->imo_multicast_ifp = ifp; break; case IP_MULTICAST_TTL: /* * Set the IP time-to-live for outgoing multicast packets. */ if (m == NULL || m->m_len != 1) { error = EINVAL; break; } imo->imo_multicast_ttl = *(mtod(m, u_char *)); break; case IP_MULTICAST_LOOP: /* * Set the loopback flag for outgoing multicast packets. * Must be zero or one. */ if (m == NULL || m->m_len != 1 || (loop = *(mtod(m, u_char *))) > 1) { error = EINVAL; break; } imo->imo_multicast_loop = loop; break; case IP_ADD_MEMBERSHIP: /* * Add a multicast group membership. * Group must be a valid IP multicast address. */ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { error = EINVAL; break; } mreq = mtod(m, struct ip_mreq *); if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) { error = EINVAL; break; } /* * If no interface address was provided, use the interface of * the route to the given multicast address. */ if (mreq->imr_interface.s_addr == INADDR_ANY) { ro.ro_rt = NULL; dst = satosin(&ro.ro_dst); dst->sin_len = sizeof(*dst); dst->sin_family = AF_INET; dst->sin_addr = mreq->imr_multiaddr; rtalloc(&ro); if (ro.ro_rt == NULL) { error = EADDRNOTAVAIL; break; } ifp = ro.ro_rt->rt_ifp; rtfree(ro.ro_rt); } else { INADDR_TO_IFP(mreq->imr_interface, ifp); } /* * See if we found an interface, and confirm that it * supports multicast. */ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; } /* * See if the membership already exists or if all the * membership slots are full. */ for (i = 0; i < imo->imo_num_memberships; ++i) { if (imo->imo_membership[i]->inm_ifp == ifp && imo->imo_membership[i]->inm_addr.s_addr == mreq->imr_multiaddr.s_addr) break; } if (i < imo->imo_num_memberships) { error = EADDRINUSE; break; } if (i == IP_MAX_MEMBERSHIPS) { error = ETOOMANYREFS; break; } /* * Everything looks good; add a new record to the multicast * address list for the given interface. */ if ((imo->imo_membership[i] = in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { error = ENOBUFS; break; } ++imo->imo_num_memberships; break; case IP_DROP_MEMBERSHIP: /* * Drop a multicast group membership. * Group must be a valid IP multicast address. */ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { error = EINVAL; break; } mreq = mtod(m, struct ip_mreq *); if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) { error = EINVAL; break; } /* * If an interface address was specified, get a pointer * to its ifnet structure. */ if (mreq->imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { INADDR_TO_IFP(mreq->imr_interface, ifp); if (ifp == NULL) { error = EADDRNOTAVAIL; break; } } /* * Find the membership in the membership array. */ for (i = 0; i < imo->imo_num_memberships; ++i) { if ((ifp == NULL || imo->imo_membership[i]->inm_ifp == ifp) && imo->imo_membership[i]->inm_addr.s_addr == mreq->imr_multiaddr.s_addr) break; } if (i == imo->imo_num_memberships) { error = EADDRNOTAVAIL; break; } /* * Give up the multicast address record to which the * membership points. */ in_delmulti(imo->imo_membership[i]); /* * Remove the gap in the membership array. */ for (++i; i < imo->imo_num_memberships; ++i) imo->imo_membership[i-1] = imo->imo_membership[i]; --imo->imo_num_memberships; break; default: error = EOPNOTSUPP; break; } /* * If all options have default values, no need to keep the mbuf. */ if (imo->imo_multicast_ifp == NULL && imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && imo->imo_num_memberships == 0) { free(*imop, M_IPMOPTS); *imop = NULL; } return (error);}/* * Return the IP multicast options in response to user getsockopt(). */intip_getmoptions(optname, imo, mp) int optname; register struct ip_moptions *imo; register struct mbuf **mp;{ u_char *ttl; u_char *loop; struct in_addr *addr; struct in_ifaddr *ia; *mp = m_get(M_WAIT, MT_SOOPTS); switch (optname) { case IP_MULTICAST_IF: addr = mtod(*mp, struct in_addr *); (*mp)->m_len = sizeof(struct in_addr); if (imo == NULL || imo->imo_multicast_ifp == NULL) addr->s_addr = INADDR_ANY; else { IFP_TO_IA(imo->imo_multicast_ifp, ia); addr->s_addr = (ia == NULL) ? INADDR_ANY : ia->ia_addr.sin_addr.s_addr; } return (0); case IP_MULTICAST_TTL: ttl = mtod(*mp, u_char *); (*mp)->m_len = 1; *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL : imo->imo_multicast_ttl; return (0); case IP_MULTICAST_LOOP: loop = mtod(*mp, u_char *); (*mp)->m_len = 1; *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP : imo->imo_multicast_loop; return (0); default: return (EOPNOTSUPP); }}/* * Discard the IP multicast options. */voidip_freemoptions(imo) register struct ip_moptions *imo;{ register int i; if (imo != NULL) { for (i = 0; i < imo->imo_num_memberships; ++i) in_delmulti(imo->imo_membership[i]); free(imo, M_IPMOPTS); }}#endif /* NOTUSED_BY_PMON *//* * Routine called from ip_output() to loop back a copy of an IP multicast * packet to the input queue of a specified interface. Note that this * calls the output routine of the loopback "driver", but with an interface * pointer that might NOT be &loif -- easier than replicating that code here. */static voidip_mloopback(ifp, m, dst) struct ifnet *ifp; register struct mbuf *m; register struct sockaddr_in *dst;{ register struct ip *ip; struct mbuf *copym; copym = m_copy(m, 0, M_COPYALL); if (copym != NULL) { /* * We don't bother to fragment if the IP length is greater * than the interface's MTU. Can this possibly matter? */ ip = mtod(copym, struct ip *); ip->ip_len = htons((u_int16_t)ip->ip_len); ip->ip_off = htons((u_int16_t)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); (void) looutput(ifp, copym, sintosa(dst), NULL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -