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