📄 ip_output.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ip_output.c 4.5 (ULTRIX) 11/9/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 * * * 02-Aug-90 lp * Fix ROUTETOIF case in route cache extensions. * * 31-Jul-90 jsd * word align optlen for mips when inserting IP options * * 7-Jul-90 lp * FDDI performance. * * 2-Jan-90 U. Sinkewicz * Performance enhancements to uniprocessor kernel. * * 11-14-89 Ursula Sinkewicz * Removed lk_ifnet and lk_in_ifaddr to coincide with * slip changes. * * 10-18-89 Uttam Shikarpur * * Added counters for network management to keep track * * of: 1) Number of IP packets sent out (ips_totalsent) * * 2) Number of error-free IP packets discarded * * (ips_outdiscard) * * 3) Number of packets that were fragmented * * (ips_outpktsfrag) * * 4) Number of fragments that were created * * (ips_outtotalfrag) * * 5) Number of packets that could not be fragmented * * (ips_outfragsfail) * * * * 30-May-89 U. Sinkewicz * Added support for nonsymmetric network drivers. * * 11-Apr-89 Ursula Sinkewicz * Picked up memenemy changes from 2/10/89 making ip options * long word aligned before insertion in output packets. * * 27-Mar-89 Ursula Sinkewicz * Lowered ipl on lk_rtentry, lk_ifnet, lk_in_ifaddr as per * lp changes on 3/16/89. * * 3 Mar 89 Ursula Sinkewicz * Added support for new directory layout to smp file. * * 13 Feb 89 Ursula Sinkewicz * SMP: Added lk_in_ifaddr, lk_ifnet. * * 15-Jan-88 lp * Merge of final 43BSD changes. * * Larry Cohen - 01/28/87 * Add ip ouput control routine and ip options processing * routine * * * Chet Juszczak - 03/12/86 * * Add new packet fragmentation code for NFS * * * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * ip_output.c 7.6 (Berkeley) 6/20/87 */#include "../h/param.h"#include "../h/cpudata.h"#include "../h/user.h"#include "../h/buf.h"#include "../h/conf.h"#include "../h/proc.h"#include "../h/mbuf.h"#include "../h/errno.h"#include "../h/protosw.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/smp_lock.h"#include "../net/net/if.h"#include "../net/net/route.h"#include "../net/netinet/in.h"#include "../net/netinet/in_systm.h"#include "../net/netinet/in_var.h"#include "../net/netinet/in_pcb.h"#include "../net/netinet/ip.h"#include "../net/netinet/ip_var.h"#ifdef vax#include "../machine/mtpr.h"#endifstruct mbuf *ip_insertoptions();/* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed./* * SMP: enter from tcp_output and protosw with NO locks set. * Results in a hack in tcp_output but you cannot require * locks be set coming in because of possibility of being triggered from * protosw. Further, there is no data manipulated here that is under the * control of the socket lock. */ip_output(m, opt, ro, flags, so) struct mbuf *m; struct mbuf *opt; struct route *ro; int flags; struct socket *so;{ register struct ip *ip; register struct ifnet *ifp; int len, hlen = sizeof (struct ip), off, error = 0; struct route iproute; struct sockaddr_in *dst; int saveaffinity; if (opt) m = ip_insertoptions(m, opt, &hlen); ip = mtod(m, struct ip *); /* * Fill in IP header. */ if ((flags & IP_FORWARDING) == 0) { ip->ip_v = IPVERSION; ip->ip_off &= IP_DF; ip->ip_id = htons(ip_id++);/* * CJ - SUN has the following line before this if statement. */ ip->ip_hl = hlen >> 2; } else hlen = ip->ip_hl << 2; /* * Route packet. */ RTLOCK(); if (ro == 0) { ro = &iproute; bzero((caddr_t)ro, sizeof (*ro)); } dst = (struct sockaddr_in *)&ro->ro_dst; /* * If there is a cached route, * check that it is to the same destination * and is still up. If not, free it and try again. */ if (ro->ro_rt && (ro->ro_rt->rt_flags & RTF_UP) && dst->sin_addr.s_addr == ip->ip_dst.s_addr) { if((ifp = ro->ro_rt->rt_ifp) && (flags&IP_ROUTETOIF)) { RTUNLOCK(); goto fastout; } } else { if(ro->ro_rt) { rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } } if (ro->ro_rt == 0) { dst->sin_family = AF_INET; dst->sin_addr = ip->ip_dst; } /* * If routing to interface only, * short circuit routing lookup. */ if (flags & IP_ROUTETOIF) { struct in_ifaddr *ia; ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst); if (ia == 0) ia = in_iaonnetof(in_netof(ip->ip_dst)); if (ia == 0) { error = ENETUNREACH; RTUNLOCK(); IPSTAT(ips_outdiscard++); /* a packet was discarded*/ goto bad; } ifp = ia->ia_ifp; } else { if (ro->ro_rt == 0) rtalloc(ro); if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { if (in_localaddr(ip->ip_dst)) error = EHOSTUNREACH; else error = ENETUNREACH; RTUNLOCK(); IPSTAT(ips_outdiscard++); /* a packet was discarded */ goto bad; } ro->ro_rt->rt_use++; if (ro->ro_rt->rt_flags & RTF_GATEWAY) dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; } RTUNLOCK(); /* * Look for broadcast address and * and verify user is allowed to send * such a packet. */ if (in_broadcast(dst->sin_addr)) { if ((ifp->if_flags & IFF_BROADCAST) == 0) { error = EADDRNOTAVAIL; IPSTAT(ips_outdiscard++); /* a packet was discarded */ goto bad; } if ((flags & IP_ALLOWBROADCAST) == 0) { error = EACCES; goto bad; } /* don't allow broadcast messages to be fragmented */ if (ip->ip_len > ifp->if_mtu) { error = EMSGSIZE; IPSTAT(ips_outfragsfail++); /* a packet could * not be fragmented */ goto bad; } }fastout: /* * If source address not specified yet, use address * of outgoing interface. */ if (ip->ip_src.s_addr == INADDR_ANY) { register struct in_ifaddr *ia; for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp) { ip->ip_src = IA_SIN(ia)->sin_addr; break; } } /* * If small enough for interface, can just send directly. */ if (ip->ip_len <= ifp->if_mtu) { ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = in_cksum(m, hlen); /* Support for nonsymm net devices. 8.9.88.us */ if ( !smp) error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); else { if ( ifp->d_affinity != boot_cpu_mask) error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); else{ if (so){ so->ref = 24; smp_unlock(&so->lk_socket); } CALL_TO_NONSMP_DRIVER( (*ifp), saveaffinity); error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); RETURN_FROM_NONSMP_DRIVER( (*ifp), saveaffinity); if ( so ){ smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; } } } /* for network management */ if (!error) /* if there was no error while sending */ IPSTAT(ips_totalsent++); /* counter for total * IP packets sent out. */ goto done; } /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. */ if (ip->ip_off & IP_DF) { error = EMSGSIZE; IPSTAT(ips_outfragsfail++); /* a packet could * not be fragmented */ goto bad; } len = (ifp->if_mtu - hlen) &~ 7; if (len < 8) { error = EMSGSIZE; IPSTAT(ips_outfragsfail++); /* a packet could * not be fragmented */ goto bad; } /* * CJ: * Call to new packet fragmentation routine. * Added for NFS. */ if (hlen == sizeof (struct ip) && ip_frag2(m, ip, len, &error, ifp, dst, so)) { IPSTAT(ips_outpktsfrag++); /* packet was successfully frag.*/ goto done; } /* * Discard IP header from logical mbuf for m_copy's sake. * Loop through length of segment, make a copy of each * part and output. */ m->m_len -= sizeof (struct ip); m->m_off += sizeof (struct ip); for (off = 0; off < ip->ip_len-hlen; off += len) { struct mbuf *mh = m_get(M_DONTWAIT, MT_DATA); struct ip *mhip; if (mh == 0) { error = ENOBUFS; IPSTAT(ips_outdiscard++); /* a packet was discarded */ goto bad; } mh->m_off = MMAXOFF - hlen; mhip = mtod(mh, struct ip *); *mhip = *ip; if (hlen > sizeof (struct ip)) { int olen = ip_optcopy(ip, mhip, off); mh->m_len = sizeof (struct ip) + olen; } else mh->m_len = sizeof (struct ip); mhip->ip_off = (off >> 3) + (ip->ip_off & ~IP_MF); if (ip->ip_off & IP_MF) mhip->ip_off |= IP_MF; if (off + len >= ip->ip_len-hlen) len = mhip->ip_len = ip->ip_len - hlen - off; else { mhip->ip_len = len; mhip->ip_off |= IP_MF; } mhip->ip_len += sizeof (struct ip); mhip->ip_len = htons((u_short)mhip->ip_len); mh->m_next = m_copy(m, off, len); if (mh->m_next == 0) { (void) m_free(mh); error = ENOBUFS; /* ??? */ IPSTAT(ips_outdiscard++); /* a packet was discarded */ goto bad; } mhip->ip_off = htons((u_short)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = in_cksum(mh, hlen); /* Support for nonsymm net devices. 8.9.88.us */ if (!smp) error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst); else{ if (ifp->d_affinity != boot_cpu_mask) error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst); else{ if (so){ so->ref = 25; smp_unlock(&so->lk_socket); } CALL_TO_NONSMP_DRIVER( (*ifp),saveaffinity); error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst); RETURN_FROM_NONSMP_DRIVER( (*ifp), saveaffinity);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -