123745Skarels /* 244371Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 544481Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*57433Sandrew * @(#)ip_output.c 7.27 (Berkeley) 01/08/93 823745Skarels */ 94571Swnj 1056531Sbostic #include <sys/param.h> 1156531Sbostic #include <sys/malloc.h> 1256531Sbostic #include <sys/mbuf.h> 1356531Sbostic #include <sys/errno.h> 1456531Sbostic #include <sys/protosw.h> 1556531Sbostic #include <sys/socket.h> 1656531Sbostic #include <sys/socketvar.h> 1710893Ssam 1856531Sbostic #include <net/if.h> 1956531Sbostic #include <net/route.h> 2010893Ssam 2156531Sbostic #include <netinet/in.h> 2256531Sbostic #include <netinet/in_systm.h> 2356531Sbostic #include <netinet/ip.h> 2456531Sbostic #include <netinet/in_pcb.h> 2556531Sbostic #include <netinet/in_var.h> 2656531Sbostic #include <netinet/ip_var.h> 274496Swnj 2812460Ssam #ifdef vax 2956531Sbostic #include <machine/mtpr.h> 3012460Ssam #endif 3110893Ssam 3254716Ssklower struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); 3354716Ssklower static void ip_mloopback __P((struct ifnet *, struct mbuf *, 3454716Ssklower struct sockaddr_in *)); 3524814Skarels 3624814Skarels /* 3724814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 3831037Skarels * header (with len, off, ttl, proto, tos, src, dst). 3931037Skarels * The mbuf chain containing the packet will be freed. 4031037Skarels * The mbuf opt, if present, will not be freed. 4124814Skarels */ 4254716Ssklower int 43*57433Sandrew ip_output(m0, opt, ro, flags, imo) 4433598Skarels struct mbuf *m0; 455085Swnj struct mbuf *opt; 466339Ssam struct route *ro; 4712417Ssam int flags; 4854716Ssklower struct ip_moptions *imo; 494496Swnj { 5033598Skarels register struct ip *ip, *mhip; 515085Swnj register struct ifnet *ifp; 5233598Skarels register struct mbuf *m = m0; 5333598Skarels register int hlen = sizeof (struct ip); 5433598Skarels int len, off, error = 0; 556339Ssam struct route iproute; 5616602Ssam struct sockaddr_in *dst; 5740794Ssklower struct in_ifaddr *ia; 584496Swnj 5945014Skarels #ifdef DIAGNOSTIC 6045014Skarels if ((m->m_flags & M_PKTHDR) == 0) 6145014Skarels panic("ip_output no HDR"); 6245014Skarels #endif 6333598Skarels if (opt) { 6433598Skarels m = ip_insertoptions(m, opt, &len); 6533598Skarels hlen = len; 6633598Skarels } 6724814Skarels ip = mtod(m, struct ip *); 684924Swnj /* 694924Swnj * Fill in IP header. 704924Swnj */ 7112417Ssam if ((flags & IP_FORWARDING) == 0) { 7212417Ssam ip->ip_v = IPVERSION; 7312417Ssam ip->ip_off &= IP_DF; 7412417Ssam ip->ip_id = htons(ip_id++); 7516545Skarels ip->ip_hl = hlen >> 2; 76*57433Sandrew ipstat.ips_localout++; 7739185Ssklower } else { 7824814Skarels hlen = ip->ip_hl << 2; 7939185Ssklower } 804545Swnj /* 817155Swnj * Route packet. 825085Swnj */ 836339Ssam if (ro == 0) { 846339Ssam ro = &iproute; 856339Ssam bzero((caddr_t)ro, sizeof (*ro)); 865085Swnj } 8716602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 8826156Skarels /* 8926156Skarels * If there is a cached route, 9026156Skarels * check that it is to the same destination 9126156Skarels * and is still up. If not, free it and try again. 9226156Skarels */ 9326156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 9426156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 9526156Skarels RTFREE(ro->ro_rt); 9626156Skarels ro->ro_rt = (struct rtentry *)0; 9726156Skarels } 986339Ssam if (ro->ro_rt == 0) { 9916602Ssam dst->sin_family = AF_INET; 10037318Skarels dst->sin_len = sizeof(*dst); 10116602Ssam dst->sin_addr = ip->ip_dst; 10226058Skarels } 10326058Skarels /* 10426058Skarels * If routing to interface only, 10526058Skarels * short circuit routing lookup. 10626058Skarels */ 10726058Skarels if (flags & IP_ROUTETOIF) { 10827196Skarels 10934500Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); 11027196Skarels if (ia == 0) 11127196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 11226058Skarels if (ia == 0) { 113*57433Sandrew ipstat.ips_noroute++; 11426058Skarels error = ENETUNREACH; 11526058Skarels goto bad; 11626058Skarels } 11726058Skarels ifp = ia->ia_ifp; 11826058Skarels } else { 11926058Skarels if (ro->ro_rt == 0) 12026058Skarels rtalloc(ro); 12144371Skarels if (ro->ro_rt == 0) { 122*57433Sandrew ipstat.ips_noroute++; 12344371Skarels error = EHOSTUNREACH; 12426058Skarels goto bad; 12526058Skarels } 12640794Ssklower ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; 12744371Skarels ifp = ro->ro_rt->rt_ifp; 12826058Skarels ro->ro_rt->rt_use++; 12930761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 13037318Skarels dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1316339Ssam } 13254716Ssklower if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 13354716Ssklower struct in_multi *inm; 13454716Ssklower extern struct ifnet loif; 13554716Ssklower extern struct socket *ip_mrouter; 13654716Ssklower 13754716Ssklower m->m_flags |= M_MCAST; 13854716Ssklower /* 13954716Ssklower * IP destination address is multicast. Make sure "dst" 14054716Ssklower * still points to the address in "ro". (It may have been 14154716Ssklower * changed to point to a gateway address, above.) 14254716Ssklower */ 14354716Ssklower dst = (struct sockaddr_in *)&ro->ro_dst; 14454716Ssklower /* 14554716Ssklower * See if the caller provided any multicast options 14654716Ssklower */ 14754716Ssklower if (imo != NULL) { 14854716Ssklower ip->ip_ttl = imo->imo_multicast_ttl; 14954716Ssklower if (imo->imo_multicast_ifp != NULL) 15054716Ssklower ifp = imo->imo_multicast_ifp; 15154716Ssklower } else 15254716Ssklower ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; 15354716Ssklower /* 15454716Ssklower * Confirm that the outgoing interface supports multicast. 15554716Ssklower */ 15654716Ssklower if ((ifp->if_flags & IFF_MULTICAST) == 0) { 157*57433Sandrew ipstat.ips_noroute++; 15854716Ssklower error = ENETUNREACH; 15954716Ssklower goto bad; 16054716Ssklower } 16154716Ssklower /* 16254716Ssklower * If source address not specified yet, use address 16354716Ssklower * of outgoing interface. 16454716Ssklower */ 16554716Ssklower if (ip->ip_src.s_addr == INADDR_ANY) { 16654716Ssklower register struct in_ifaddr *ia; 16754716Ssklower 16854716Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 16954716Ssklower if (ia->ia_ifp == ifp) { 17054716Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 17154716Ssklower break; 17254716Ssklower } 17354716Ssklower } 17454716Ssklower 17554716Ssklower IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); 17654716Ssklower if (inm != NULL && 17754716Ssklower (imo == NULL || imo->imo_multicast_loop)) { 17854716Ssklower /* 17954716Ssklower * If we belong to the destination multicast group 18054716Ssklower * on the outgoing interface, and the caller did not 18154716Ssklower * forbid loopback, loop back a copy. 18254716Ssklower */ 18354716Ssklower ip_mloopback(ifp, m, dst); 18454716Ssklower } 18554716Ssklower #ifdef MROUTING 18654716Ssklower else if (ip_mrouter && (flags & IP_FORWARDING) == 0) { 18754716Ssklower /* 18854716Ssklower * If we are acting as a multicast router, perform 18954716Ssklower * multicast forwarding as if the packet had just 19054716Ssklower * arrived on the interface to which we are about 19154716Ssklower * to send. The multicast forwarding function 19254716Ssklower * recursively calls this function, using the 19354716Ssklower * IP_FORWARDING flag to prevent infinite recursion. 19454716Ssklower * 19554716Ssklower * Multicasts that are looped back by ip_mloopback(), 19654716Ssklower * above, will be forwarded by the ip_input() routine, 19754716Ssklower * if necessary. 19854716Ssklower */ 19954716Ssklower if (ip_mforward(m, ifp) != 0) { 20054716Ssklower m_freem(m); 20154716Ssklower goto done; 20254716Ssklower } 20354716Ssklower } 20454716Ssklower #endif 20554716Ssklower /* 20654716Ssklower * Multicasts with a time-to-live of zero may be looped- 20754716Ssklower * back, above, but must not be transmitted on a network. 20854716Ssklower * Also, multicasts addressed to the loopback interface 20954716Ssklower * are not sent -- the above call to ip_mloopback() will 21054716Ssklower * loop back a copy if this host actually belongs to the 21154716Ssklower * destination group on the loopback interface. 21254716Ssklower */ 21354716Ssklower if (ip->ip_ttl == 0 || ifp == &loif) { 21454716Ssklower m_freem(m); 21554716Ssklower goto done; 21654716Ssklower } 21754716Ssklower 21854716Ssklower goto sendit; 21954716Ssklower } 22023745Skarels #ifndef notdef 2217155Swnj /* 22223745Skarels * If source address not specified yet, use address 22323745Skarels * of outgoing interface. 22423745Skarels */ 22540794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 22640794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 22723745Skarels #endif 22823745Skarels /* 22910402Ssam * Look for broadcast address and 23010402Ssam * and verify user is allowed to send 23110146Ssam * such a packet. 2327155Swnj */ 23318375Skarels if (in_broadcast(dst->sin_addr)) { 23410146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 23510146Ssam error = EADDRNOTAVAIL; 23610146Ssam goto bad; 23710146Ssam } 23812417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 2397155Swnj error = EACCES; 2406339Ssam goto bad; 2416505Ssam } 24210146Ssam /* don't allow broadcast messages to be fragmented */ 24344372Skarels if ((u_short)ip->ip_len > ifp->if_mtu) { 24410146Ssam error = EMSGSIZE; 24510146Ssam goto bad; 24610146Ssam } 24737318Skarels m->m_flags |= M_BCAST; 248*57433Sandrew } else 249*57433Sandrew m->m_flags &= ~M_BCAST; 2506339Ssam 25154716Ssklower sendit: 2525085Swnj /* 2534924Swnj * If small enough for interface, can just send directly. 2544545Swnj */ 25544372Skarels if ((u_short)ip->ip_len <= ifp->if_mtu) { 2565085Swnj ip->ip_len = htons((u_short)ip->ip_len); 2575085Swnj ip->ip_off = htons((u_short)ip->ip_off); 2585085Swnj ip->ip_sum = 0; 2595085Swnj ip->ip_sum = in_cksum(m, hlen); 26040794Ssklower error = (*ifp->if_output)(ifp, m, 26140794Ssklower (struct sockaddr *)dst, ro->ro_rt); 2627155Swnj goto done; 2634908Swnj } 2644924Swnj /* 2654924Swnj * Too large for interface; fragment if possible. 2664924Swnj * Must be able to put at least 8 bytes per fragment. 2674924Swnj */ 2686505Ssam if (ip->ip_off & IP_DF) { 2696505Ssam error = EMSGSIZE; 270*57433Sandrew ipstat.ips_cantfrag++; 2714924Swnj goto bad; 2726505Ssam } 2735085Swnj len = (ifp->if_mtu - hlen) &~ 7; 2746505Ssam if (len < 8) { 2756505Ssam error = EMSGSIZE; 2764924Swnj goto bad; 2776505Ssam } 2784924Swnj 27933744Skarels { 28033744Skarels int mhlen, firstlen = len; 28137318Skarels struct mbuf **mnext = &m->m_nextpkt; 28233744Skarels 2834924Swnj /* 28433744Skarels * Loop through length of segment after first fragment, 28533744Skarels * make new header and copy data of each part and link onto chain. 2864924Swnj */ 28733598Skarels m0 = m; 28833744Skarels mhlen = sizeof (struct ip); 28944372Skarels for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 29037318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 29133598Skarels if (m == 0) { 2926505Ssam error = ENOBUFS; 293*57433Sandrew ipstat.ips_odropped++; 29434820Skarels goto sendorfree; 2956505Ssam } 29637318Skarels m->m_data += max_linkhdr; 29733598Skarels mhip = mtod(m, struct ip *); 2984924Swnj *mhip = *ip; 2994952Swnj if (hlen > sizeof (struct ip)) { 30033744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 30133598Skarels mhip->ip_hl = mhlen >> 2; 30233744Skarels } 30333598Skarels m->m_len = mhlen; 30433744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 30516545Skarels if (ip->ip_off & IP_MF) 30616545Skarels mhip->ip_off |= IP_MF; 30744372Skarels if (off + len >= (u_short)ip->ip_len) 30844372Skarels len = (u_short)ip->ip_len - off; 30933598Skarels else 3104924Swnj mhip->ip_off |= IP_MF; 31133598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 31233598Skarels m->m_next = m_copy(m0, off, len); 31333598Skarels if (m->m_next == 0) { 3146505Ssam error = ENOBUFS; /* ??? */ 315*57433Sandrew ipstat.ips_odropped++; 31633744Skarels goto sendorfree; 3174674Swnj } 31837318Skarels m->m_pkthdr.len = mhlen + len; 31937318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 3205892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 3215892Sroot mhip->ip_sum = 0; 32233598Skarels mhip->ip_sum = in_cksum(m, mhlen); 32333744Skarels *mnext = m; 32437318Skarels mnext = &m->m_nextpkt; 32539185Ssklower ipstat.ips_ofragments++; 3264924Swnj } 32733744Skarels /* 32833744Skarels * Update first fragment by trimming what's been copied out 32933744Skarels * and updating header, then send each fragment (in order). 33033744Skarels */ 33140254Smckusick m = m0; 33244372Skarels m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 33337318Skarels m->m_pkthdr.len = hlen + firstlen; 33437318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 33533983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 33633744Skarels ip->ip_sum = 0; 33740254Smckusick ip->ip_sum = in_cksum(m, hlen); 33833744Skarels sendorfree: 33933744Skarels for (m = m0; m; m = m0) { 34037318Skarels m0 = m->m_nextpkt; 34137318Skarels m->m_nextpkt = 0; 34233744Skarels if (error == 0) 34333744Skarels error = (*ifp->if_output)(ifp, m, 34440794Ssklower (struct sockaddr *)dst, ro->ro_rt); 34533744Skarels else 34633744Skarels m_freem(m); 34733744Skarels } 348*57433Sandrew 349*57433Sandrew if (error == 0) 350*57433Sandrew ipstat.ips_fragmented++; 35133744Skarels } 3527155Swnj done: 35312417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 3547155Swnj RTFREE(ro->ro_rt); 3556505Ssam return (error); 35633744Skarels bad: 35733744Skarels m_freem(m0); 35833744Skarels goto done; 3594924Swnj } 3604924Swnj 3614924Swnj /* 36224814Skarels * Insert IP options into preformed packet. 36324814Skarels * Adjust IP destination as required for IP source routing, 36424814Skarels * as indicated by a non-zero in_addr at the start of the options. 36524814Skarels */ 36624814Skarels struct mbuf * 36724814Skarels ip_insertoptions(m, opt, phlen) 36824814Skarels register struct mbuf *m; 36924814Skarels struct mbuf *opt; 37024814Skarels int *phlen; 37124814Skarels { 37224814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 37324814Skarels struct mbuf *n; 37424814Skarels register struct ip *ip = mtod(m, struct ip *); 37526385Skarels unsigned optlen; 37624814Skarels 37724814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 37844372Skarels if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 37944372Skarels return (m); /* XXX should fail */ 38024814Skarels if (p->ipopt_dst.s_addr) 38124814Skarels ip->ip_dst = p->ipopt_dst; 38237318Skarels if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 38337318Skarels MGETHDR(n, M_DONTWAIT, MT_HEADER); 38424814Skarels if (n == 0) 38524814Skarels return (m); 38637318Skarels n->m_pkthdr.len = m->m_pkthdr.len + optlen; 38724814Skarels m->m_len -= sizeof(struct ip); 38837318Skarels m->m_data += sizeof(struct ip); 38924814Skarels n->m_next = m; 39024814Skarels m = n; 39124814Skarels m->m_len = optlen + sizeof(struct ip); 39237318Skarels m->m_data += max_linkhdr; 39324814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 39424814Skarels } else { 39537318Skarels m->m_data -= optlen; 39624814Skarels m->m_len += optlen; 39737318Skarels m->m_pkthdr.len += optlen; 39824814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 39924814Skarels } 40024814Skarels ip = mtod(m, struct ip *); 40126385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 40224814Skarels *phlen = sizeof(struct ip) + optlen; 40324814Skarels ip->ip_len += optlen; 40424814Skarels return (m); 40524814Skarels } 40624814Skarels 40724814Skarels /* 40833744Skarels * Copy options from ip to jp, 40933744Skarels * omitting those not copied during fragmentation. 4104924Swnj */ 41154716Ssklower int 41233744Skarels ip_optcopy(ip, jp) 4134924Swnj struct ip *ip, *jp; 4144924Swnj { 4154924Swnj register u_char *cp, *dp; 4164924Swnj int opt, optlen, cnt; 4174924Swnj 4184924Swnj cp = (u_char *)(ip + 1); 4194924Swnj dp = (u_char *)(jp + 1); 4204924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 4214924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 4224924Swnj opt = cp[0]; 4234924Swnj if (opt == IPOPT_EOL) 4244924Swnj break; 425*57433Sandrew if (opt == IPOPT_NOP) { 426*57433Sandrew /* Preserve for IP mcast tunnel's LSRR alignment. */ 427*57433Sandrew *dp++ = IPOPT_NOP; 4284924Swnj optlen = 1; 429*57433Sandrew continue; 430*57433Sandrew } else 43124814Skarels optlen = cp[IPOPT_OLEN]; 43233744Skarels /* bogus lengths should have been caught by ip_dooptions */ 43333744Skarels if (optlen > cnt) 43433744Skarels optlen = cnt; 43533744Skarels if (IPOPT_COPIED(opt)) { 4364952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 4374924Swnj dp += optlen; 4384674Swnj } 4394545Swnj } 4404924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 4414924Swnj *dp++ = IPOPT_EOL; 4424924Swnj return (optlen); 4434496Swnj } 44424814Skarels 44524814Skarels /* 44624814Skarels * IP socket option processing. 44724814Skarels */ 44854716Ssklower int 44944371Skarels ip_ctloutput(op, so, level, optname, mp) 45024814Skarels int op; 45124814Skarels struct socket *so; 45224814Skarels int level, optname; 45344371Skarels struct mbuf **mp; 45424814Skarels { 45544371Skarels register struct inpcb *inp = sotoinpcb(so); 45644371Skarels register struct mbuf *m = *mp; 45744371Skarels register int optval; 45824814Skarels int error = 0; 45924814Skarels 46024814Skarels if (level != IPPROTO_IP) 46151273Ssklower goto freeit; 46224814Skarels else switch (op) { 46324814Skarels 46424814Skarels case PRCO_SETOPT: 46524814Skarels switch (optname) { 46624814Skarels case IP_OPTIONS: 46745014Skarels #ifdef notyet 46844371Skarels case IP_RETOPTS: 46944371Skarels return (ip_pcbopts(optname, &inp->inp_options, m)); 47045014Skarels #else 47145014Skarels return (ip_pcbopts(&inp->inp_options, m)); 47245014Skarels #endif 47324814Skarels 47444371Skarels case IP_TOS: 47544371Skarels case IP_TTL: 47644371Skarels case IP_RECVOPTS: 47744371Skarels case IP_RECVRETOPTS: 47844371Skarels case IP_RECVDSTADDR: 47944371Skarels if (m->m_len != sizeof(int)) 48044371Skarels error = EINVAL; 48144371Skarels else { 48244371Skarels optval = *mtod(m, int *); 48345014Skarels switch (optname) { 48444371Skarels 48544371Skarels case IP_TOS: 48644371Skarels inp->inp_ip.ip_tos = optval; 48744371Skarels break; 48844371Skarels 48944371Skarels case IP_TTL: 49045567Ssklower inp->inp_ip.ip_ttl = optval; 49144371Skarels break; 49244371Skarels #define OPTSET(bit) \ 49344371Skarels if (optval) \ 49444371Skarels inp->inp_flags |= bit; \ 49544371Skarels else \ 49644371Skarels inp->inp_flags &= ~bit; 49744371Skarels 49844371Skarels case IP_RECVOPTS: 49944371Skarels OPTSET(INP_RECVOPTS); 50044371Skarels break; 50144371Skarels 50244371Skarels case IP_RECVRETOPTS: 50344371Skarels OPTSET(INP_RECVRETOPTS); 50444371Skarels break; 50544371Skarels 50644371Skarels case IP_RECVDSTADDR: 50744371Skarels OPTSET(INP_RECVDSTADDR); 50844371Skarels break; 50944371Skarels } 51044371Skarels } 51144371Skarels break; 51244371Skarels #undef OPTSET 51344371Skarels 51454716Ssklower case IP_MULTICAST_IF: 51554716Ssklower case IP_MULTICAST_TTL: 51654716Ssklower case IP_MULTICAST_LOOP: 51754716Ssklower case IP_ADD_MEMBERSHIP: 51854716Ssklower case IP_DROP_MEMBERSHIP: 51954716Ssklower error = ip_setmoptions(optname, &inp->inp_moptions, m); 52054716Ssklower break; 52154716Ssklower 52251273Ssklower freeit: 52324814Skarels default: 52424814Skarels error = EINVAL; 52524814Skarels break; 52624814Skarels } 52744371Skarels if (m) 52844371Skarels (void)m_free(m); 52924814Skarels break; 53024814Skarels 53124814Skarels case PRCO_GETOPT: 53224814Skarels switch (optname) { 53324814Skarels case IP_OPTIONS: 53445014Skarels case IP_RETOPTS: 53544371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 53624814Skarels if (inp->inp_options) { 53744371Skarels m->m_len = inp->inp_options->m_len; 53824814Skarels bcopy(mtod(inp->inp_options, caddr_t), 53944371Skarels mtod(m, caddr_t), (unsigned)m->m_len); 54024814Skarels } else 54144371Skarels m->m_len = 0; 54224814Skarels break; 54344371Skarels 54444371Skarels case IP_TOS: 54544371Skarels case IP_TTL: 54644371Skarels case IP_RECVOPTS: 54744371Skarels case IP_RECVRETOPTS: 54844371Skarels case IP_RECVDSTADDR: 54944371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 55044371Skarels m->m_len = sizeof(int); 55145014Skarels switch (optname) { 55244371Skarels 55344371Skarels case IP_TOS: 55444371Skarels optval = inp->inp_ip.ip_tos; 55544371Skarels break; 55644371Skarels 55744371Skarels case IP_TTL: 55845567Ssklower optval = inp->inp_ip.ip_ttl; 55944371Skarels break; 56044371Skarels 56144371Skarels #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 56244371Skarels 56344371Skarels case IP_RECVOPTS: 56444371Skarels optval = OPTBIT(INP_RECVOPTS); 56544371Skarels break; 56644371Skarels 56744371Skarels case IP_RECVRETOPTS: 56844371Skarels optval = OPTBIT(INP_RECVRETOPTS); 56944371Skarels break; 57044371Skarels 57144371Skarels case IP_RECVDSTADDR: 57244371Skarels optval = OPTBIT(INP_RECVDSTADDR); 57344371Skarels break; 57444371Skarels } 57544371Skarels *mtod(m, int *) = optval; 57644371Skarels break; 57744371Skarels 57854716Ssklower case IP_MULTICAST_IF: 57954716Ssklower case IP_MULTICAST_TTL: 58054716Ssklower case IP_MULTICAST_LOOP: 58154716Ssklower case IP_ADD_MEMBERSHIP: 58254716Ssklower case IP_DROP_MEMBERSHIP: 58354716Ssklower error = ip_getmoptions(optname, inp->inp_moptions, mp); 58454716Ssklower break; 58554716Ssklower 58624814Skarels default: 58724814Skarels error = EINVAL; 58824814Skarels break; 58924814Skarels } 59024814Skarels break; 59124814Skarels } 59224814Skarels return (error); 59324814Skarels } 59424814Skarels 59524814Skarels /* 59626036Skarels * Set up IP options in pcb for insertion in output packets. 59726036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 59826036Skarels * with destination address if source routed. 59924814Skarels */ 60054716Ssklower int 60145014Skarels #ifdef notyet 60245014Skarels ip_pcbopts(optname, pcbopt, m) 60345014Skarels int optname; 60445014Skarels #else 60526036Skarels ip_pcbopts(pcbopt, m) 60645014Skarels #endif 60726036Skarels struct mbuf **pcbopt; 60826036Skarels register struct mbuf *m; 60924814Skarels { 61024814Skarels register cnt, optlen; 61124814Skarels register u_char *cp; 61224814Skarels u_char opt; 61324814Skarels 61424814Skarels /* turn off any old options */ 61526036Skarels if (*pcbopt) 61626385Skarels (void)m_free(*pcbopt); 61726036Skarels *pcbopt = 0; 61824814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 61924814Skarels /* 62024814Skarels * Only turning off any previous options. 62124814Skarels */ 62224814Skarels if (m) 62326385Skarels (void)m_free(m); 62424814Skarels return (0); 62524814Skarels } 62624814Skarels 62724814Skarels #ifndef vax 62824814Skarels if (m->m_len % sizeof(long)) 62924814Skarels goto bad; 63024814Skarels #endif 63124814Skarels /* 63224814Skarels * IP first-hop destination address will be stored before 63324814Skarels * actual options; move other options back 63424814Skarels * and clear it when none present. 63524814Skarels */ 63637318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 63724814Skarels goto bad; 63824814Skarels cnt = m->m_len; 63924814Skarels m->m_len += sizeof(struct in_addr); 64024814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 64126385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 64224814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 64324814Skarels 64424814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 64524814Skarels opt = cp[IPOPT_OPTVAL]; 64624814Skarels if (opt == IPOPT_EOL) 64724814Skarels break; 64824814Skarels if (opt == IPOPT_NOP) 64924814Skarels optlen = 1; 65024814Skarels else { 65124814Skarels optlen = cp[IPOPT_OLEN]; 65224814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 65324814Skarels goto bad; 65424814Skarels } 65524814Skarels switch (opt) { 65624814Skarels 65724814Skarels default: 65824814Skarels break; 65924814Skarels 66024814Skarels case IPOPT_LSRR: 66124814Skarels case IPOPT_SSRR: 66224814Skarels /* 66324814Skarels * user process specifies route as: 66424814Skarels * ->A->B->C->D 66524814Skarels * D must be our final destination (but we can't 66624814Skarels * check that since we may not have connected yet). 66724814Skarels * A is first hop destination, which doesn't appear in 66824814Skarels * actual IP option, but is stored before the options. 66924814Skarels */ 67024814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 67124814Skarels goto bad; 67224814Skarels m->m_len -= sizeof(struct in_addr); 67324814Skarels cnt -= sizeof(struct in_addr); 67424814Skarels optlen -= sizeof(struct in_addr); 67524814Skarels cp[IPOPT_OLEN] = optlen; 67624814Skarels /* 67724814Skarels * Move first hop before start of options. 67824814Skarels */ 67926385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 68024814Skarels sizeof(struct in_addr)); 68124814Skarels /* 68224814Skarels * Then copy rest of options back 68324814Skarels * to close up the deleted entry. 68424814Skarels */ 68526385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 68626385Skarels sizeof(struct in_addr)), 68726385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 68826385Skarels (unsigned)cnt + sizeof(struct in_addr)); 68924814Skarels break; 69024814Skarels } 69124814Skarels } 69237318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 69337318Skarels goto bad; 69426036Skarels *pcbopt = m; 69524814Skarels return (0); 69624814Skarels 69724814Skarels bad: 69826385Skarels (void)m_free(m); 69924814Skarels return (EINVAL); 70024814Skarels } 70154716Ssklower 70254716Ssklower /* 70354716Ssklower * Set the IP multicast options in response to user setsockopt(). 70454716Ssklower */ 70554716Ssklower int 70654716Ssklower ip_setmoptions(optname, imop, m) 70754716Ssklower int optname; 70854716Ssklower struct ip_moptions **imop; 70954716Ssklower struct mbuf *m; 71054716Ssklower { 71154716Ssklower register int error = 0; 71254716Ssklower u_char loop; 71354716Ssklower register int i; 71454716Ssklower struct in_addr addr; 71554716Ssklower register struct ip_mreq *mreq; 71654716Ssklower register struct ifnet *ifp; 71754716Ssklower register struct ip_moptions *imo = *imop; 71854716Ssklower struct route ro; 71954716Ssklower register struct sockaddr_in *dst; 72054716Ssklower 72154716Ssklower if (imo == NULL) { 72254716Ssklower /* 72354716Ssklower * No multicast option buffer attached to the pcb; 72454716Ssklower * allocate one and initialize to default values. 72554716Ssklower */ 72654716Ssklower imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, 72754716Ssklower M_WAITOK); 72854716Ssklower 72954716Ssklower if (imo == NULL) 73054716Ssklower return (ENOBUFS); 73154716Ssklower *imop = imo; 73254716Ssklower imo->imo_multicast_ifp = NULL; 73354716Ssklower imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 73454716Ssklower imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 73554716Ssklower imo->imo_num_memberships = 0; 73654716Ssklower } 73754716Ssklower 73854716Ssklower switch (optname) { 73954716Ssklower 74054716Ssklower case IP_MULTICAST_IF: 74154716Ssklower /* 74254716Ssklower * Select the interface for outgoing multicast packets. 74354716Ssklower */ 74454716Ssklower if (m == NULL || m->m_len != sizeof(struct in_addr)) { 74554716Ssklower error = EINVAL; 74654716Ssklower break; 74754716Ssklower } 74854716Ssklower addr = *(mtod(m, struct in_addr *)); 74954716Ssklower /* 75054716Ssklower * INADDR_ANY is used to remove a previous selection. 75154716Ssklower * When no interface is selected, a default one is 75254716Ssklower * chosen every time a multicast packet is sent. 75354716Ssklower */ 75454716Ssklower if (addr.s_addr == INADDR_ANY) { 75554716Ssklower imo->imo_multicast_ifp = NULL; 75654716Ssklower break; 75754716Ssklower } 75854716Ssklower /* 75954716Ssklower * The selected interface is identified by its local 76054716Ssklower * IP address. Find the interface and confirm that 76154716Ssklower * it supports multicasting. 76254716Ssklower */ 76354716Ssklower INADDR_TO_IFP(addr, ifp); 76454716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 76554716Ssklower error = EADDRNOTAVAIL; 76654716Ssklower break; 76754716Ssklower } 76854716Ssklower imo->imo_multicast_ifp = ifp; 76954716Ssklower break; 77054716Ssklower 77154716Ssklower case IP_MULTICAST_TTL: 77254716Ssklower /* 77354716Ssklower * Set the IP time-to-live for outgoing multicast packets. 77454716Ssklower */ 77554716Ssklower if (m == NULL || m->m_len != 1) { 77654716Ssklower error = EINVAL; 77754716Ssklower break; 77854716Ssklower } 77954716Ssklower imo->imo_multicast_ttl = *(mtod(m, u_char *)); 78054716Ssklower break; 78154716Ssklower 78254716Ssklower case IP_MULTICAST_LOOP: 78354716Ssklower /* 78454716Ssklower * Set the loopback flag for outgoing multicast packets. 78554716Ssklower * Must be zero or one. 78654716Ssklower */ 78754716Ssklower if (m == NULL || m->m_len != 1 || 78854716Ssklower (loop = *(mtod(m, u_char *))) > 1) { 78954716Ssklower error = EINVAL; 79054716Ssklower break; 79154716Ssklower } 79254716Ssklower imo->imo_multicast_loop = loop; 79354716Ssklower break; 79454716Ssklower 79554716Ssklower case IP_ADD_MEMBERSHIP: 79654716Ssklower /* 79754716Ssklower * Add a multicast group membership. 79854716Ssklower * Group must be a valid IP multicast address. 79954716Ssklower */ 80054716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 80154716Ssklower error = EINVAL; 80254716Ssklower break; 80354716Ssklower } 80454716Ssklower mreq = mtod(m, struct ip_mreq *); 80554716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 80654716Ssklower error = EINVAL; 80754716Ssklower break; 80854716Ssklower } 80954716Ssklower /* 81054716Ssklower * If no interface address was provided, use the interface of 81154716Ssklower * the route to the given multicast address. 81254716Ssklower */ 81354716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) { 81454716Ssklower ro.ro_rt = NULL; 81554716Ssklower dst = (struct sockaddr_in *)&ro.ro_dst; 81654716Ssklower dst->sin_len = sizeof(*dst); 81754716Ssklower dst->sin_family = AF_INET; 81854716Ssklower dst->sin_addr = mreq->imr_multiaddr; 81954716Ssklower rtalloc(&ro); 82054716Ssklower if (ro.ro_rt == NULL) { 82154716Ssklower error = EADDRNOTAVAIL; 82254716Ssklower break; 82354716Ssklower } 82454716Ssklower ifp = ro.ro_rt->rt_ifp; 82554716Ssklower rtfree(ro.ro_rt); 82654716Ssklower } 82754716Ssklower else { 82854716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 82954716Ssklower } 83054716Ssklower /* 83154716Ssklower * See if we found an interface, and confirm that it 83254716Ssklower * supports multicast. 83354716Ssklower */ 83454716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 83554716Ssklower error = EADDRNOTAVAIL; 83654716Ssklower break; 83754716Ssklower } 83854716Ssklower /* 83954716Ssklower * See if the membership already exists or if all the 84054716Ssklower * membership slots are full. 84154716Ssklower */ 84254716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 84354716Ssklower if (imo->imo_membership[i]->inm_ifp == ifp && 84454716Ssklower imo->imo_membership[i]->inm_addr.s_addr 84554716Ssklower == mreq->imr_multiaddr.s_addr) 84654716Ssklower break; 84754716Ssklower } 84854716Ssklower if (i < imo->imo_num_memberships) { 84954716Ssklower error = EADDRINUSE; 85054716Ssklower break; 85154716Ssklower } 85254716Ssklower if (i == IP_MAX_MEMBERSHIPS) { 85354716Ssklower error = ETOOMANYREFS; 85454716Ssklower break; 85554716Ssklower } 85654716Ssklower /* 85754716Ssklower * Everything looks good; add a new record to the multicast 85854716Ssklower * address list for the given interface. 85954716Ssklower */ 86054716Ssklower if ((imo->imo_membership[i] = 86154716Ssklower in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { 86254716Ssklower error = ENOBUFS; 86354716Ssklower break; 86454716Ssklower } 86554716Ssklower ++imo->imo_num_memberships; 86654716Ssklower break; 86754716Ssklower 86854716Ssklower case IP_DROP_MEMBERSHIP: 86954716Ssklower /* 87054716Ssklower * Drop a multicast group membership. 87154716Ssklower * Group must be a valid IP multicast address. 87254716Ssklower */ 87354716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 87454716Ssklower error = EINVAL; 87554716Ssklower break; 87654716Ssklower } 87754716Ssklower mreq = mtod(m, struct ip_mreq *); 87854716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 87954716Ssklower error = EINVAL; 88054716Ssklower break; 88154716Ssklower } 88254716Ssklower /* 88354716Ssklower * If an interface address was specified, get a pointer 88454716Ssklower * to its ifnet structure. 88554716Ssklower */ 88654716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) 88754716Ssklower ifp = NULL; 88854716Ssklower else { 88954716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 89054716Ssklower if (ifp == NULL) { 89154716Ssklower error = EADDRNOTAVAIL; 89254716Ssklower break; 89354716Ssklower } 89454716Ssklower } 89554716Ssklower /* 89654716Ssklower * Find the membership in the membership array. 89754716Ssklower */ 89854716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 89954716Ssklower if ((ifp == NULL || 90054716Ssklower imo->imo_membership[i]->inm_ifp == ifp) && 90154716Ssklower imo->imo_membership[i]->inm_addr.s_addr == 90254716Ssklower mreq->imr_multiaddr.s_addr) 90354716Ssklower break; 90454716Ssklower } 90554716Ssklower if (i == imo->imo_num_memberships) { 90654716Ssklower error = EADDRNOTAVAIL; 90754716Ssklower break; 90854716Ssklower } 90954716Ssklower /* 91054716Ssklower * Give up the multicast address record to which the 91154716Ssklower * membership points. 91254716Ssklower */ 91354716Ssklower in_delmulti(imo->imo_membership[i]); 91454716Ssklower /* 91554716Ssklower * Remove the gap in the membership array. 91654716Ssklower */ 91754716Ssklower for (++i; i < imo->imo_num_memberships; ++i) 91854716Ssklower imo->imo_membership[i-1] = imo->imo_membership[i]; 91954716Ssklower --imo->imo_num_memberships; 92054716Ssklower break; 92154716Ssklower 92254716Ssklower default: 92354716Ssklower error = EOPNOTSUPP; 92454716Ssklower break; 92554716Ssklower } 92654716Ssklower 92754716Ssklower /* 92854716Ssklower * If all options have default values, no need to keep the mbuf. 92954716Ssklower */ 93054716Ssklower if (imo->imo_multicast_ifp == NULL && 93154716Ssklower imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && 93254716Ssklower imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && 93354716Ssklower imo->imo_num_memberships == 0) { 93454716Ssklower free(*imop, M_IPMOPTS); 93554716Ssklower *imop = NULL; 93654716Ssklower } 93754716Ssklower 93854716Ssklower return (error); 93954716Ssklower } 94054716Ssklower 94154716Ssklower /* 94254716Ssklower * Return the IP multicast options in response to user getsockopt(). 94354716Ssklower */ 94454716Ssklower int 94554716Ssklower ip_getmoptions(optname, imo, mp) 94654716Ssklower int optname; 94754716Ssklower register struct ip_moptions *imo; 94854716Ssklower register struct mbuf **mp; 94954716Ssklower { 95054716Ssklower u_char *ttl; 95154716Ssklower u_char *loop; 95254716Ssklower struct in_addr *addr; 95354716Ssklower struct in_ifaddr *ia; 95454716Ssklower 95554716Ssklower *mp = m_get(M_WAIT, MT_SOOPTS); 95654716Ssklower 95754716Ssklower switch (optname) { 95854716Ssklower 95954716Ssklower case IP_MULTICAST_IF: 96054716Ssklower addr = mtod(*mp, struct in_addr *); 96154716Ssklower (*mp)->m_len = sizeof(struct in_addr); 96254716Ssklower if (imo == NULL || imo->imo_multicast_ifp == NULL) 96354716Ssklower addr->s_addr = INADDR_ANY; 96454716Ssklower else { 96554716Ssklower IFP_TO_IA(imo->imo_multicast_ifp, ia); 96654716Ssklower addr->s_addr = (ia == NULL) ? INADDR_ANY 96754716Ssklower : IA_SIN(ia)->sin_addr.s_addr; 96854716Ssklower } 96954716Ssklower return (0); 97054716Ssklower 97154716Ssklower case IP_MULTICAST_TTL: 97254716Ssklower ttl = mtod(*mp, u_char *); 97354716Ssklower (*mp)->m_len = 1; 97454716Ssklower *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL 97554716Ssklower : imo->imo_multicast_ttl; 97654716Ssklower return (0); 97754716Ssklower 97854716Ssklower case IP_MULTICAST_LOOP: 97954716Ssklower loop = mtod(*mp, u_char *); 98054716Ssklower (*mp)->m_len = 1; 98154716Ssklower *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP 98254716Ssklower : imo->imo_multicast_loop; 98354716Ssklower return (0); 98454716Ssklower 98554716Ssklower default: 98654716Ssklower return (EOPNOTSUPP); 98754716Ssklower } 98854716Ssklower } 98954716Ssklower 99054716Ssklower /* 99154716Ssklower * Discard the IP multicast options. 99254716Ssklower */ 99354716Ssklower void 99454716Ssklower ip_freemoptions(imo) 99554716Ssklower register struct ip_moptions *imo; 99654716Ssklower { 99754716Ssklower register int i; 99854716Ssklower 99954716Ssklower if (imo != NULL) { 100054716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) 100154716Ssklower in_delmulti(imo->imo_membership[i]); 100254716Ssklower free(imo, M_IPMOPTS); 100354716Ssklower } 100454716Ssklower } 100554716Ssklower 100654716Ssklower /* 100754716Ssklower * Routine called from ip_output() to loop back a copy of an IP multicast 100854716Ssklower * packet to the input queue of a specified interface. Note that this 100954716Ssklower * calls the output routine of the loopback "driver", but with an interface 101054716Ssklower * pointer that might NOT be &loif -- easier than replicating that code here. 101154716Ssklower */ 101254716Ssklower static void 101354716Ssklower ip_mloopback(ifp, m, dst) 101454716Ssklower struct ifnet *ifp; 101554716Ssklower register struct mbuf *m; 101654716Ssklower register struct sockaddr_in *dst; 101754716Ssklower { 101854716Ssklower register struct ip *ip; 101954716Ssklower struct mbuf *copym; 102054716Ssklower 102154716Ssklower copym = m_copy(m, 0, M_COPYALL); 102254716Ssklower if (copym != NULL) { 102354716Ssklower /* 102454716Ssklower * We don't bother to fragment if the IP length is greater 102554716Ssklower * than the interface's MTU. Can this possibly matter? 102654716Ssklower */ 102754716Ssklower ip = mtod(copym, struct ip *); 102854716Ssklower ip->ip_len = htons((u_short)ip->ip_len); 102954716Ssklower ip->ip_off = htons((u_short)ip->ip_off); 103054716Ssklower ip->ip_sum = 0; 103154716Ssklower ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); 103254716Ssklower (void) looutput(ifp, copym, (struct sockaddr *)dst); 103354716Ssklower } 103454716Ssklower } 1035