Commit | Line | Data |
---|---|---|
fc74f0c9 | 1 | /* ip_output.c 1.30 82/03/30 */ |
6e8b2eca | 2 | |
ac904f92 | 3 | #include "../h/param.h" |
dad64fdf | 4 | #include "../h/mbuf.h" |
69435e93 | 5 | #include "../h/mtpr.h" |
dad64fdf | 6 | #include "../h/socket.h" |
2b4b57cd | 7 | #include "../h/socketvar.h" |
8a13b737 BJ |
8 | #include "../net/in.h" |
9 | #include "../net/in_systm.h" | |
10 | #include "../net/if.h" | |
d52566dd | 11 | #include "../net/ip.h" |
eb44bfb2 | 12 | #include "../net/ip_var.h" |
ee787340 | 13 | #include "../net/route.h" |
ac904f92 | 14 | |
ee787340 | 15 | ip_output(m, opt, ro, allowbroadcast) |
2b4b57cd | 16 | struct mbuf *m; |
8a13b737 | 17 | struct mbuf *opt; |
ee787340 | 18 | struct route *ro; |
1e977657 | 19 | int allowbroadcast; |
ac904f92 | 20 | { |
2b4b57cd | 21 | register struct ip *ip = mtod(m, struct ip *); |
8a13b737 | 22 | register struct ifnet *ifp; |
f6311fb6 | 23 | int len, hlen = sizeof (struct ip), off; |
ee787340 | 24 | struct route iproute; |
c124e997 | 25 | struct sockaddr *dst; |
ac904f92 BJ |
26 | |
27 | COUNT(IP_OUTPUT); | |
2d82c10d | 28 | if (opt) /* XXX */ |
89e6227e | 29 | (void) m_free(opt); /* XXX */ |
e8d11875 | 30 | /* |
2b4b57cd | 31 | * Fill in IP header. |
e8d11875 | 32 | */ |
2b4b57cd BJ |
33 | ip->ip_v = IPVERSION; |
34 | ip->ip_hl = hlen >> 2; | |
35 | ip->ip_off &= IP_DF; | |
8a13b737 BJ |
36 | ip->ip_id = htons(ip_id++); |
37 | ||
38 | /* | |
c124e997 SL |
39 | * Find interface for this packet in the routing |
40 | * table. Note each interface has placed itself | |
fc74f0c9 SL |
41 | * in there at boot time, so calls to rtalloc |
42 | * degenerate to if_ifonnetof(ip->ip_dst.s_net). | |
8a13b737 | 43 | */ |
ee787340 SL |
44 | if (ro == 0) { |
45 | ro = &iproute; | |
46 | bzero((caddr_t)ro, sizeof (*ro)); | |
47 | } | |
48 | if (ro->ro_rt == 0) { | |
f6311fb6 SL |
49 | ro->ro_dst.sa_family = AF_INET; |
50 | ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = ip->ip_dst; | |
51 | rtalloc(ro); | |
fc74f0c9 SL |
52 | if (ro != &iproute) |
53 | ro->ro_rt->rt_refcnt++; | |
8a13b737 | 54 | } |
f6311fb6 SL |
55 | if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { |
56 | printf("no route to %x\n", ip->ip_dst.s_addr); | |
ee787340 | 57 | goto bad; |
f6311fb6 SL |
58 | } |
59 | dst = ro->ro_rt->rt_flags&RTF_DIRECT ? | |
60 | (struct sockaddr *)&ro->ro_dst : &ro->ro_rt->rt_gateway; | |
ee787340 SL |
61 | if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { |
62 | struct sockaddr_in *sin; | |
63 | ||
64 | sin = (struct sockaddr_in *)&ifp->if_broadaddr; | |
65 | if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) | |
66 | goto bad; | |
67 | } | |
ac904f92 | 68 | |
2b4b57cd BJ |
69 | /* |
70 | * If small enough for interface, can just send directly. | |
71 | */ | |
8a13b737 | 72 | if (ip->ip_len <= ifp->if_mtu) { |
2d82c10d | 73 | #if vax |
8a13b737 BJ |
74 | ip->ip_len = htons((u_short)ip->ip_len); |
75 | ip->ip_off = htons((u_short)ip->ip_off); | |
2d82c10d | 76 | #endif |
8a13b737 BJ |
77 | ip->ip_sum = 0; |
78 | ip->ip_sum = in_cksum(m, hlen); | |
fc74f0c9 | 79 | ro->ro_rt->rt_use++; |
c124e997 | 80 | return ((*ifp->if_output)(ifp, m, dst)); |
cdad2eb1 | 81 | } |
2b4b57cd BJ |
82 | |
83 | /* | |
84 | * Too large for interface; fragment if possible. | |
85 | * Must be able to put at least 8 bytes per fragment. | |
86 | */ | |
87 | if (ip->ip_off & IP_DF) | |
88 | goto bad; | |
8a13b737 | 89 | len = (ifp->if_mtu - hlen) &~ 7; |
2b4b57cd BJ |
90 | if (len < 8) |
91 | goto bad; | |
92 | ||
93 | /* | |
94 | * Discard IP header from logical mbuf for m_copy's sake. | |
95 | * Loop through length of segment, make a copy of each | |
96 | * part and output. | |
97 | */ | |
98 | m->m_len -= sizeof (struct ip); | |
99 | m->m_off += sizeof (struct ip); | |
0b49870f | 100 | for (off = 0; off < ip->ip_len-hlen; off += len) { |
ef9b4258 | 101 | struct mbuf *mh = m_get(M_DONTWAIT); |
2b4b57cd BJ |
102 | struct ip *mhip; |
103 | ||
104 | if (mh == 0) | |
105 | goto bad; | |
106 | mh->m_off = MMAXOFF - hlen; | |
107 | mhip = mtod(mh, struct ip *); | |
108 | *mhip = *ip; | |
4ad99bae | 109 | if (hlen > sizeof (struct ip)) { |
2b4b57cd BJ |
110 | int olen = ip_optcopy(ip, mhip, off); |
111 | mh->m_len = sizeof (struct ip) + olen; | |
112 | } else | |
113 | mh->m_len = sizeof (struct ip); | |
e8f40dc9 | 114 | mhip->ip_off = off >> 3; |
0b49870f BJ |
115 | if (off + len >= ip->ip_len-hlen) |
116 | len = mhip->ip_len = ip->ip_len - hlen - off; | |
2b4b57cd BJ |
117 | else { |
118 | mhip->ip_len = len; | |
119 | mhip->ip_off |= IP_MF; | |
98444525 | 120 | } |
e8f40dc9 BJ |
121 | mhip->ip_len += sizeof (struct ip); |
122 | #if vax | |
123 | mhip->ip_len = htons((u_short)mhip->ip_len); | |
124 | #endif | |
2b4b57cd BJ |
125 | mh->m_next = m_copy(m, off, len); |
126 | if (mh->m_next == 0) { | |
2752c877 | 127 | (void) m_free(mh); |
2b4b57cd | 128 | goto bad; |
98444525 | 129 | } |
e8f40dc9 | 130 | #if vax |
0b49870f | 131 | mhip->ip_off = htons((u_short)mhip->ip_off); |
e8f40dc9 | 132 | #endif |
0b49870f BJ |
133 | mhip->ip_sum = 0; |
134 | mhip->ip_sum = in_cksum(mh, hlen); | |
fc74f0c9 | 135 | ro->ro_rt->rt_use++; |
c124e997 | 136 | if ((*ifp->if_output)(ifp, mh, dst) == 0) |
8a13b737 | 137 | goto bad; |
2b4b57cd | 138 | } |
8a13b737 BJ |
139 | m_freem(m); |
140 | return (1); | |
2b4b57cd BJ |
141 | bad: |
142 | m_freem(m); | |
8a13b737 | 143 | return (0); |
2b4b57cd BJ |
144 | } |
145 | ||
146 | /* | |
147 | * Copy options from ip to jp. | |
4ad99bae | 148 | * If off is 0 all options are copied |
2b4b57cd BJ |
149 | * otherwise copy selectively. |
150 | */ | |
151 | ip_optcopy(ip, jp, off) | |
152 | struct ip *ip, *jp; | |
153 | int off; | |
154 | { | |
155 | register u_char *cp, *dp; | |
156 | int opt, optlen, cnt; | |
157 | ||
4ad99bae | 158 | COUNT(IP_OPTCOPY); |
2b4b57cd BJ |
159 | cp = (u_char *)(ip + 1); |
160 | dp = (u_char *)(jp + 1); | |
161 | cnt = (ip->ip_hl << 2) - sizeof (struct ip); | |
162 | for (; cnt > 0; cnt -= optlen, cp += optlen) { | |
163 | opt = cp[0]; | |
164 | if (opt == IPOPT_EOL) | |
165 | break; | |
166 | if (opt == IPOPT_NOP) | |
167 | optlen = 1; | |
168 | else | |
169 | optlen = cp[1]; | |
170 | if (optlen > cnt) /* XXX */ | |
171 | optlen = cnt; /* XXX */ | |
172 | if (off == 0 || IPOPT_COPIED(opt)) { | |
4ad99bae | 173 | bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); |
2b4b57cd | 174 | dp += optlen; |
ac904f92 | 175 | } |
e8d11875 | 176 | } |
2b4b57cd BJ |
177 | for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) |
178 | *dp++ = IPOPT_EOL; | |
179 | return (optlen); | |
ac904f92 | 180 | } |