1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)ip_output.c 7.6 (Berkeley) 06/20/87 7 */ 8 9 #include "param.h" 10 #include "mbuf.h" 11 #include "errno.h" 12 #include "protosw.h" 13 #include "socket.h" 14 #include "socketvar.h" 15 16 #include "../net/if.h" 17 #include "../net/route.h" 18 19 #include "in.h" 20 #include "in_pcb.h" 21 #include "in_systm.h" 22 #include "in_var.h" 23 #include "ip.h" 24 #include "ip_var.h" 25 26 #ifdef vax 27 #include "../machine/mtpr.h" 28 #endif 29 30 struct mbuf *ip_insertoptions(); 31 32 /* 33 * IP output. The packet in mbuf chain m contains a skeletal IP 34 * header (with len, off, ttl, proto, tos, src, dst). 35 * The mbuf chain containing the packet will be freed. 36 * The mbuf opt, if present, will not be freed. 37 */ 38 ip_output(m, opt, ro, flags) 39 struct mbuf *m; 40 struct mbuf *opt; 41 struct route *ro; 42 int flags; 43 { 44 register struct ip *ip; 45 register struct ifnet *ifp; 46 int len, hlen = sizeof (struct ip), off, error = 0; 47 struct route iproute; 48 struct sockaddr_in *dst; 49 50 if (opt) 51 m = ip_insertoptions(m, opt, &hlen); 52 ip = mtod(m, struct ip *); 53 /* 54 * Fill in IP header. 55 */ 56 if ((flags & IP_FORWARDING) == 0) { 57 ip->ip_v = IPVERSION; 58 ip->ip_off &= IP_DF; 59 ip->ip_id = htons(ip_id++); 60 ip->ip_hl = hlen >> 2; 61 } else 62 hlen = ip->ip_hl << 2; 63 64 /* 65 * Route packet. 66 */ 67 if (ro == 0) { 68 ro = &iproute; 69 bzero((caddr_t)ro, sizeof (*ro)); 70 } 71 dst = (struct sockaddr_in *)&ro->ro_dst; 72 /* 73 * If there is a cached route, 74 * check that it is to the same destination 75 * and is still up. If not, free it and try again. 76 */ 77 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 78 dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 79 RTFREE(ro->ro_rt); 80 ro->ro_rt = (struct rtentry *)0; 81 } 82 if (ro->ro_rt == 0) { 83 dst->sin_family = AF_INET; 84 dst->sin_addr = ip->ip_dst; 85 } 86 /* 87 * If routing to interface only, 88 * short circuit routing lookup. 89 */ 90 if (flags & IP_ROUTETOIF) { 91 struct in_ifaddr *ia; 92 93 ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst); 94 if (ia == 0) 95 ia = in_iaonnetof(in_netof(ip->ip_dst)); 96 if (ia == 0) { 97 error = ENETUNREACH; 98 goto bad; 99 } 100 ifp = ia->ia_ifp; 101 } else { 102 if (ro->ro_rt == 0) 103 rtalloc(ro); 104 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 105 if (in_localaddr(ip->ip_dst)) 106 error = EHOSTUNREACH; 107 else 108 error = ENETUNREACH; 109 goto bad; 110 } 111 ro->ro_rt->rt_use++; 112 if (ro->ro_rt->rt_flags & RTF_GATEWAY) 113 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; 114 } 115 #ifndef notdef 116 /* 117 * If source address not specified yet, use address 118 * of outgoing interface. 119 */ 120 if (ip->ip_src.s_addr == INADDR_ANY) { 121 register struct in_ifaddr *ia; 122 123 for (ia = in_ifaddr; ia; ia = ia->ia_next) 124 if (ia->ia_ifp == ifp) { 125 ip->ip_src = IA_SIN(ia)->sin_addr; 126 break; 127 } 128 } 129 #endif 130 /* 131 * Look for broadcast address and 132 * and verify user is allowed to send 133 * such a packet. 134 */ 135 if (in_broadcast(dst->sin_addr)) { 136 if ((ifp->if_flags & IFF_BROADCAST) == 0) { 137 error = EADDRNOTAVAIL; 138 goto bad; 139 } 140 if ((flags & IP_ALLOWBROADCAST) == 0) { 141 error = EACCES; 142 goto bad; 143 } 144 /* don't allow broadcast messages to be fragmented */ 145 if (ip->ip_len > ifp->if_mtu) { 146 error = EMSGSIZE; 147 goto bad; 148 } 149 } 150 151 /* 152 * If small enough for interface, can just send directly. 153 */ 154 if (ip->ip_len <= ifp->if_mtu) { 155 ip->ip_len = htons((u_short)ip->ip_len); 156 ip->ip_off = htons((u_short)ip->ip_off); 157 ip->ip_sum = 0; 158 ip->ip_sum = in_cksum(m, hlen); 159 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); 160 goto done; 161 } 162 163 /* 164 * Too large for interface; fragment if possible. 165 * Must be able to put at least 8 bytes per fragment. 166 */ 167 if (ip->ip_off & IP_DF) { 168 error = EMSGSIZE; 169 goto bad; 170 } 171 len = (ifp->if_mtu - hlen) &~ 7; 172 if (len < 8) { 173 error = EMSGSIZE; 174 goto bad; 175 } 176 177 /* 178 * Discard IP header from logical mbuf for m_copy's sake. 179 * Loop through length of segment, make a copy of each 180 * part and output. 181 */ 182 m->m_len -= sizeof (struct ip); 183 m->m_off += sizeof (struct ip); 184 for (off = 0; off < ip->ip_len-hlen; off += len) { 185 struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER); 186 struct ip *mhip; 187 188 if (mh == 0) { 189 error = ENOBUFS; 190 goto bad; 191 } 192 mh->m_off = MMAXOFF - hlen; 193 mhip = mtod(mh, struct ip *); 194 *mhip = *ip; 195 if (hlen > sizeof (struct ip)) { 196 int olen = ip_optcopy(ip, mhip, off); 197 mh->m_len = sizeof (struct ip) + olen; 198 } else 199 mh->m_len = sizeof (struct ip); 200 mhip->ip_off = (off >> 3) + (ip->ip_off & ~IP_MF); 201 if (ip->ip_off & IP_MF) 202 mhip->ip_off |= IP_MF; 203 if (off + len >= ip->ip_len-hlen) 204 len = mhip->ip_len = ip->ip_len - hlen - off; 205 else { 206 mhip->ip_len = len; 207 mhip->ip_off |= IP_MF; 208 } 209 mhip->ip_len += sizeof (struct ip); 210 mhip->ip_len = htons((u_short)mhip->ip_len); 211 mh->m_next = m_copy(m, off, len); 212 if (mh->m_next == 0) { 213 (void) m_free(mh); 214 error = ENOBUFS; /* ??? */ 215 goto bad; 216 } 217 mhip->ip_off = htons((u_short)mhip->ip_off); 218 mhip->ip_sum = 0; 219 mhip->ip_sum = in_cksum(mh, hlen); 220 if (error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst)) 221 break; 222 } 223 bad: 224 m_freem(m); 225 done: 226 if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 227 RTFREE(ro->ro_rt); 228 return (error); 229 } 230 231 /* 232 * Insert IP options into preformed packet. 233 * Adjust IP destination as required for IP source routing, 234 * as indicated by a non-zero in_addr at the start of the options. 235 */ 236 struct mbuf * 237 ip_insertoptions(m, opt, phlen) 238 register struct mbuf *m; 239 struct mbuf *opt; 240 int *phlen; 241 { 242 register struct ipoption *p = mtod(opt, struct ipoption *); 243 struct mbuf *n; 244 register struct ip *ip = mtod(m, struct ip *); 245 unsigned optlen; 246 247 optlen = opt->m_len - sizeof(p->ipopt_dst); 248 if (p->ipopt_dst.s_addr) 249 ip->ip_dst = p->ipopt_dst; 250 if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { 251 MGET(n, M_DONTWAIT, MT_HEADER); 252 if (n == 0) 253 return (m); 254 m->m_len -= sizeof(struct ip); 255 m->m_off += sizeof(struct ip); 256 n->m_next = m; 257 m = n; 258 m->m_off = MMAXOFF - sizeof(struct ip) - optlen; 259 m->m_len = optlen + sizeof(struct ip); 260 bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 261 } else { 262 m->m_off -= optlen; 263 m->m_len += optlen; 264 ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 265 } 266 ip = mtod(m, struct ip *); 267 bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 268 *phlen = sizeof(struct ip) + optlen; 269 ip->ip_len += optlen; 270 return (m); 271 } 272 273 /* 274 * Copy options from ip to jp. 275 * If off is 0 all options are copied 276 * otherwise copy selectively. 277 */ 278 ip_optcopy(ip, jp, off) 279 struct ip *ip, *jp; 280 int off; 281 { 282 register u_char *cp, *dp; 283 int opt, optlen, cnt; 284 285 cp = (u_char *)(ip + 1); 286 dp = (u_char *)(jp + 1); 287 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 288 for (; cnt > 0; cnt -= optlen, cp += optlen) { 289 opt = cp[0]; 290 if (opt == IPOPT_EOL) 291 break; 292 if (opt == IPOPT_NOP) 293 optlen = 1; 294 else 295 optlen = cp[IPOPT_OLEN]; 296 if (optlen > cnt) /* XXX */ 297 optlen = cnt; /* XXX */ 298 if (off == 0 || IPOPT_COPIED(opt)) { 299 bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 300 dp += optlen; 301 } 302 } 303 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 304 *dp++ = IPOPT_EOL; 305 return (optlen); 306 } 307 308 /* 309 * IP socket option processing. 310 */ 311 ip_ctloutput(op, so, level, optname, m) 312 int op; 313 struct socket *so; 314 int level, optname; 315 struct mbuf **m; 316 { 317 int error = 0; 318 struct inpcb *inp = sotoinpcb(so); 319 320 if (level != IPPROTO_IP) 321 error = EINVAL; 322 else switch (op) { 323 324 case PRCO_SETOPT: 325 switch (optname) { 326 case IP_OPTIONS: 327 return (ip_pcbopts(&inp->inp_options, *m)); 328 329 default: 330 error = EINVAL; 331 break; 332 } 333 break; 334 335 case PRCO_GETOPT: 336 switch (optname) { 337 case IP_OPTIONS: 338 *m = m_get(M_WAIT, MT_SOOPTS); 339 if (inp->inp_options) { 340 (*m)->m_off = inp->inp_options->m_off; 341 (*m)->m_len = inp->inp_options->m_len; 342 bcopy(mtod(inp->inp_options, caddr_t), 343 mtod(*m, caddr_t), (unsigned)(*m)->m_len); 344 } else 345 (*m)->m_len = 0; 346 break; 347 default: 348 error = EINVAL; 349 break; 350 } 351 break; 352 } 353 if (op == PRCO_SETOPT && *m) 354 (void)m_free(*m); 355 return (error); 356 } 357 358 /* 359 * Set up IP options in pcb for insertion in output packets. 360 * Store in mbuf with pointer in pcbopt, adding pseudo-option 361 * with destination address if source routed. 362 */ 363 ip_pcbopts(pcbopt, m) 364 struct mbuf **pcbopt; 365 register struct mbuf *m; 366 { 367 register cnt, optlen; 368 register u_char *cp; 369 u_char opt; 370 371 /* turn off any old options */ 372 if (*pcbopt) 373 (void)m_free(*pcbopt); 374 *pcbopt = 0; 375 if (m == (struct mbuf *)0 || m->m_len == 0) { 376 /* 377 * Only turning off any previous options. 378 */ 379 if (m) 380 (void)m_free(m); 381 return (0); 382 } 383 384 #ifndef vax 385 if (m->m_len % sizeof(long)) 386 goto bad; 387 #endif 388 /* 389 * IP first-hop destination address will be stored before 390 * actual options; move other options back 391 * and clear it when none present. 392 */ 393 #if MAX_IPOPTLEN >= MMAXOFF - MMINOFF 394 if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) 395 goto bad; 396 #else 397 if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) 398 goto bad; 399 #endif 400 cnt = m->m_len; 401 m->m_len += sizeof(struct in_addr); 402 cp = mtod(m, u_char *) + sizeof(struct in_addr); 403 ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 404 bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 405 406 for (; cnt > 0; cnt -= optlen, cp += optlen) { 407 opt = cp[IPOPT_OPTVAL]; 408 if (opt == IPOPT_EOL) 409 break; 410 if (opt == IPOPT_NOP) 411 optlen = 1; 412 else { 413 optlen = cp[IPOPT_OLEN]; 414 if (optlen <= IPOPT_OLEN || optlen > cnt) 415 goto bad; 416 } 417 switch (opt) { 418 419 default: 420 break; 421 422 case IPOPT_LSRR: 423 case IPOPT_SSRR: 424 /* 425 * user process specifies route as: 426 * ->A->B->C->D 427 * D must be our final destination (but we can't 428 * check that since we may not have connected yet). 429 * A is first hop destination, which doesn't appear in 430 * actual IP option, but is stored before the options. 431 */ 432 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 433 goto bad; 434 m->m_len -= sizeof(struct in_addr); 435 cnt -= sizeof(struct in_addr); 436 optlen -= sizeof(struct in_addr); 437 cp[IPOPT_OLEN] = optlen; 438 /* 439 * Move first hop before start of options. 440 */ 441 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 442 sizeof(struct in_addr)); 443 /* 444 * Then copy rest of options back 445 * to close up the deleted entry. 446 */ 447 ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 448 sizeof(struct in_addr)), 449 (caddr_t)&cp[IPOPT_OFFSET+1], 450 (unsigned)cnt + sizeof(struct in_addr)); 451 break; 452 } 453 } 454 *pcbopt = m; 455 return (0); 456 457 bad: 458 (void)m_free(m); 459 return (EINVAL); 460 } 461