123745Skarels /* 257967Sandrew * Copyright (c) 1982, 1986, 1988, 1990, 1993 Regents of the University 357967Sandrew * of California. All rights reserved. 423745Skarels * 557967Sandrew * %sccs.include.redist.c% 632787Sbostic * 7*58655Sandrew * @(#)ip_output.c 7.31 (Berkeley) 03/12/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 4357433Sandrew 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 */ 7157966Sandrew if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 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; 7657433Sandrew 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) { 11357433Sandrew 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) { 12257433Sandrew 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 13654716Ssklower m->m_flags |= M_MCAST; 13754716Ssklower /* 13854716Ssklower * IP destination address is multicast. Make sure "dst" 13954716Ssklower * still points to the address in "ro". (It may have been 14054716Ssklower * changed to point to a gateway address, above.) 14154716Ssklower */ 14254716Ssklower dst = (struct sockaddr_in *)&ro->ro_dst; 14354716Ssklower /* 14454716Ssklower * See if the caller provided any multicast options 14554716Ssklower */ 14654716Ssklower if (imo != NULL) { 14754716Ssklower ip->ip_ttl = imo->imo_multicast_ttl; 14854716Ssklower if (imo->imo_multicast_ifp != NULL) 14954716Ssklower ifp = imo->imo_multicast_ifp; 15054716Ssklower } else 15154716Ssklower ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; 15254716Ssklower /* 15354716Ssklower * Confirm that the outgoing interface supports multicast. 15454716Ssklower */ 15554716Ssklower if ((ifp->if_flags & IFF_MULTICAST) == 0) { 15657433Sandrew ipstat.ips_noroute++; 15754716Ssklower error = ENETUNREACH; 15854716Ssklower goto bad; 15954716Ssklower } 16054716Ssklower /* 16154716Ssklower * If source address not specified yet, use address 16254716Ssklower * of outgoing interface. 16354716Ssklower */ 16454716Ssklower if (ip->ip_src.s_addr == INADDR_ANY) { 16554716Ssklower register struct in_ifaddr *ia; 16654716Ssklower 16754716Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 16854716Ssklower if (ia->ia_ifp == ifp) { 16954716Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 17054716Ssklower break; 17154716Ssklower } 17254716Ssklower } 17354716Ssklower 17454716Ssklower IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); 17554716Ssklower if (inm != NULL && 17654716Ssklower (imo == NULL || imo->imo_multicast_loop)) { 17754716Ssklower /* 17854716Ssklower * If we belong to the destination multicast group 17954716Ssklower * on the outgoing interface, and the caller did not 18054716Ssklower * forbid loopback, loop back a copy. 18154716Ssklower */ 18254716Ssklower ip_mloopback(ifp, m, dst); 18354716Ssklower } 18454716Ssklower #ifdef MROUTING 18557878Ssklower else { 18654716Ssklower /* 18754716Ssklower * If we are acting as a multicast router, perform 18854716Ssklower * multicast forwarding as if the packet had just 18954716Ssklower * arrived on the interface to which we are about 19054716Ssklower * to send. The multicast forwarding function 19154716Ssklower * recursively calls this function, using the 19254716Ssklower * IP_FORWARDING flag to prevent infinite recursion. 19354716Ssklower * 19454716Ssklower * Multicasts that are looped back by ip_mloopback(), 19554716Ssklower * above, will be forwarded by the ip_input() routine, 19654716Ssklower * if necessary. 19754716Ssklower */ 19857878Ssklower extern struct socket *ip_mrouter; 19957878Ssklower if (ip_mrouter && (flags & IP_FORWARDING) == 0) { 20057878Ssklower if (ip_mforward(m, ifp) != 0) { 20157878Ssklower m_freem(m); 20257878Ssklower goto done; 20357878Ssklower } 20454716Ssklower } 20554716Ssklower } 20654716Ssklower #endif 20754716Ssklower /* 20854716Ssklower * Multicasts with a time-to-live of zero may be looped- 20954716Ssklower * back, above, but must not be transmitted on a network. 21054716Ssklower * Also, multicasts addressed to the loopback interface 21154716Ssklower * are not sent -- the above call to ip_mloopback() will 21254716Ssklower * loop back a copy if this host actually belongs to the 21354716Ssklower * destination group on the loopback interface. 21454716Ssklower */ 21554716Ssklower if (ip->ip_ttl == 0 || ifp == &loif) { 21654716Ssklower m_freem(m); 21754716Ssklower goto done; 21854716Ssklower } 21954716Ssklower 22054716Ssklower goto sendit; 22154716Ssklower } 22223745Skarels #ifndef notdef 2237155Swnj /* 22423745Skarels * If source address not specified yet, use address 22523745Skarels * of outgoing interface. 22623745Skarels */ 22740794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 22840794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 22923745Skarels #endif 23023745Skarels /* 23110402Ssam * Look for broadcast address and 23210402Ssam * and verify user is allowed to send 23310146Ssam * such a packet. 2347155Swnj */ 23518375Skarels if (in_broadcast(dst->sin_addr)) { 23610146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 23710146Ssam error = EADDRNOTAVAIL; 23810146Ssam goto bad; 23910146Ssam } 24012417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 2417155Swnj error = EACCES; 2426339Ssam goto bad; 2436505Ssam } 24410146Ssam /* don't allow broadcast messages to be fragmented */ 24544372Skarels if ((u_short)ip->ip_len > ifp->if_mtu) { 24610146Ssam error = EMSGSIZE; 24710146Ssam goto bad; 24810146Ssam } 24937318Skarels m->m_flags |= M_BCAST; 25057433Sandrew } else 25157433Sandrew m->m_flags &= ~M_BCAST; 2526339Ssam 25354716Ssklower sendit: 2545085Swnj /* 2554924Swnj * If small enough for interface, can just send directly. 2564545Swnj */ 25744372Skarels if ((u_short)ip->ip_len <= ifp->if_mtu) { 2585085Swnj ip->ip_len = htons((u_short)ip->ip_len); 2595085Swnj ip->ip_off = htons((u_short)ip->ip_off); 2605085Swnj ip->ip_sum = 0; 2615085Swnj ip->ip_sum = in_cksum(m, hlen); 26240794Ssklower error = (*ifp->if_output)(ifp, m, 26340794Ssklower (struct sockaddr *)dst, ro->ro_rt); 2647155Swnj goto done; 2654908Swnj } 2664924Swnj /* 2674924Swnj * Too large for interface; fragment if possible. 2684924Swnj * Must be able to put at least 8 bytes per fragment. 2694924Swnj */ 2706505Ssam if (ip->ip_off & IP_DF) { 2716505Ssam error = EMSGSIZE; 27257433Sandrew ipstat.ips_cantfrag++; 2734924Swnj goto bad; 2746505Ssam } 2755085Swnj len = (ifp->if_mtu - hlen) &~ 7; 2766505Ssam if (len < 8) { 2776505Ssam error = EMSGSIZE; 2784924Swnj goto bad; 2796505Ssam } 2804924Swnj 28133744Skarels { 28233744Skarels int mhlen, firstlen = len; 28337318Skarels struct mbuf **mnext = &m->m_nextpkt; 28433744Skarels 2854924Swnj /* 28633744Skarels * Loop through length of segment after first fragment, 28733744Skarels * make new header and copy data of each part and link onto chain. 2884924Swnj */ 28933598Skarels m0 = m; 29033744Skarels mhlen = sizeof (struct ip); 29144372Skarels for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 29237318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 29333598Skarels if (m == 0) { 2946505Ssam error = ENOBUFS; 29557433Sandrew ipstat.ips_odropped++; 29634820Skarels goto sendorfree; 2976505Ssam } 29837318Skarels m->m_data += max_linkhdr; 29933598Skarels mhip = mtod(m, struct ip *); 3004924Swnj *mhip = *ip; 3014952Swnj if (hlen > sizeof (struct ip)) { 30233744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 30333598Skarels mhip->ip_hl = mhlen >> 2; 30433744Skarels } 30533598Skarels m->m_len = mhlen; 30633744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 30716545Skarels if (ip->ip_off & IP_MF) 30816545Skarels mhip->ip_off |= IP_MF; 30944372Skarels if (off + len >= (u_short)ip->ip_len) 31044372Skarels len = (u_short)ip->ip_len - off; 31133598Skarels else 3124924Swnj mhip->ip_off |= IP_MF; 31333598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 31433598Skarels m->m_next = m_copy(m0, off, len); 31533598Skarels if (m->m_next == 0) { 316*58655Sandrew m_free(m); 3176505Ssam error = ENOBUFS; /* ??? */ 31857433Sandrew ipstat.ips_odropped++; 31933744Skarels goto sendorfree; 3204674Swnj } 32137318Skarels m->m_pkthdr.len = mhlen + len; 32237318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 3235892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 3245892Sroot mhip->ip_sum = 0; 32533598Skarels mhip->ip_sum = in_cksum(m, mhlen); 32633744Skarels *mnext = m; 32737318Skarels mnext = &m->m_nextpkt; 32839185Ssklower ipstat.ips_ofragments++; 3294924Swnj } 33033744Skarels /* 33133744Skarels * Update first fragment by trimming what's been copied out 33233744Skarels * and updating header, then send each fragment (in order). 33333744Skarels */ 33440254Smckusick m = m0; 33544372Skarels m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 33637318Skarels m->m_pkthdr.len = hlen + firstlen; 33737318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 33833983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 33933744Skarels ip->ip_sum = 0; 34040254Smckusick ip->ip_sum = in_cksum(m, hlen); 34133744Skarels sendorfree: 34233744Skarels for (m = m0; m; m = m0) { 34337318Skarels m0 = m->m_nextpkt; 34437318Skarels m->m_nextpkt = 0; 34533744Skarels if (error == 0) 34633744Skarels error = (*ifp->if_output)(ifp, m, 34740794Ssklower (struct sockaddr *)dst, ro->ro_rt); 34833744Skarels else 34933744Skarels m_freem(m); 35033744Skarels } 35157433Sandrew 35257433Sandrew if (error == 0) 35357433Sandrew ipstat.ips_fragmented++; 35433744Skarels } 3557155Swnj done: 35612417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 3577155Swnj RTFREE(ro->ro_rt); 3586505Ssam return (error); 35933744Skarels bad: 36033744Skarels m_freem(m0); 36133744Skarels goto done; 3624924Swnj } 3634924Swnj 3644924Swnj /* 36524814Skarels * Insert IP options into preformed packet. 36624814Skarels * Adjust IP destination as required for IP source routing, 36724814Skarels * as indicated by a non-zero in_addr at the start of the options. 36824814Skarels */ 36924814Skarels struct mbuf * 37024814Skarels ip_insertoptions(m, opt, phlen) 37124814Skarels register struct mbuf *m; 37224814Skarels struct mbuf *opt; 37324814Skarels int *phlen; 37424814Skarels { 37524814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 37624814Skarels struct mbuf *n; 37724814Skarels register struct ip *ip = mtod(m, struct ip *); 37826385Skarels unsigned optlen; 37924814Skarels 38024814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 38144372Skarels if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 38244372Skarels return (m); /* XXX should fail */ 38324814Skarels if (p->ipopt_dst.s_addr) 38424814Skarels ip->ip_dst = p->ipopt_dst; 38537318Skarels if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 38637318Skarels MGETHDR(n, M_DONTWAIT, MT_HEADER); 38724814Skarels if (n == 0) 38824814Skarels return (m); 38937318Skarels n->m_pkthdr.len = m->m_pkthdr.len + optlen; 39024814Skarels m->m_len -= sizeof(struct ip); 39137318Skarels m->m_data += sizeof(struct ip); 39224814Skarels n->m_next = m; 39324814Skarels m = n; 39424814Skarels m->m_len = optlen + sizeof(struct ip); 39537318Skarels m->m_data += max_linkhdr; 39624814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 39724814Skarels } else { 39837318Skarels m->m_data -= optlen; 39924814Skarels m->m_len += optlen; 40037318Skarels m->m_pkthdr.len += optlen; 40124814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 40224814Skarels } 40324814Skarels ip = mtod(m, struct ip *); 40426385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 40524814Skarels *phlen = sizeof(struct ip) + optlen; 40624814Skarels ip->ip_len += optlen; 40724814Skarels return (m); 40824814Skarels } 40924814Skarels 41024814Skarels /* 41133744Skarels * Copy options from ip to jp, 41233744Skarels * omitting those not copied during fragmentation. 4134924Swnj */ 41454716Ssklower int 41533744Skarels ip_optcopy(ip, jp) 4164924Swnj struct ip *ip, *jp; 4174924Swnj { 4184924Swnj register u_char *cp, *dp; 4194924Swnj int opt, optlen, cnt; 4204924Swnj 4214924Swnj cp = (u_char *)(ip + 1); 4224924Swnj dp = (u_char *)(jp + 1); 4234924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 4244924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 4254924Swnj opt = cp[0]; 4264924Swnj if (opt == IPOPT_EOL) 4274924Swnj break; 42857433Sandrew if (opt == IPOPT_NOP) { 42957433Sandrew /* Preserve for IP mcast tunnel's LSRR alignment. */ 43057433Sandrew *dp++ = IPOPT_NOP; 4314924Swnj optlen = 1; 43257433Sandrew continue; 43357433Sandrew } else 43424814Skarels optlen = cp[IPOPT_OLEN]; 43533744Skarels /* bogus lengths should have been caught by ip_dooptions */ 43633744Skarels if (optlen > cnt) 43733744Skarels optlen = cnt; 43833744Skarels if (IPOPT_COPIED(opt)) { 4394952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 4404924Swnj dp += optlen; 4414674Swnj } 4424545Swnj } 4434924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 4444924Swnj *dp++ = IPOPT_EOL; 4454924Swnj return (optlen); 4464496Swnj } 44724814Skarels 44824814Skarels /* 44924814Skarels * IP socket option processing. 45024814Skarels */ 45154716Ssklower int 45244371Skarels ip_ctloutput(op, so, level, optname, mp) 45324814Skarels int op; 45424814Skarels struct socket *so; 45524814Skarels int level, optname; 45644371Skarels struct mbuf **mp; 45724814Skarels { 45844371Skarels register struct inpcb *inp = sotoinpcb(so); 45944371Skarels register struct mbuf *m = *mp; 46044371Skarels register int optval; 46124814Skarels int error = 0; 46224814Skarels 46324814Skarels if (level != IPPROTO_IP) 46451273Ssklower goto freeit; 46524814Skarels else switch (op) { 46624814Skarels 46724814Skarels case PRCO_SETOPT: 46824814Skarels switch (optname) { 46924814Skarels case IP_OPTIONS: 47045014Skarels #ifdef notyet 47144371Skarels case IP_RETOPTS: 47244371Skarels return (ip_pcbopts(optname, &inp->inp_options, m)); 47345014Skarels #else 47445014Skarels return (ip_pcbopts(&inp->inp_options, m)); 47545014Skarels #endif 47624814Skarels 47744371Skarels case IP_TOS: 47844371Skarels case IP_TTL: 47944371Skarels case IP_RECVOPTS: 48044371Skarels case IP_RECVRETOPTS: 48144371Skarels case IP_RECVDSTADDR: 48244371Skarels if (m->m_len != sizeof(int)) 48344371Skarels error = EINVAL; 48444371Skarels else { 48544371Skarels optval = *mtod(m, int *); 48645014Skarels switch (optname) { 48744371Skarels 48844371Skarels case IP_TOS: 48944371Skarels inp->inp_ip.ip_tos = optval; 49044371Skarels break; 49144371Skarels 49244371Skarels case IP_TTL: 49345567Ssklower inp->inp_ip.ip_ttl = optval; 49444371Skarels break; 49544371Skarels #define OPTSET(bit) \ 49644371Skarels if (optval) \ 49744371Skarels inp->inp_flags |= bit; \ 49844371Skarels else \ 49944371Skarels inp->inp_flags &= ~bit; 50044371Skarels 50144371Skarels case IP_RECVOPTS: 50244371Skarels OPTSET(INP_RECVOPTS); 50344371Skarels break; 50444371Skarels 50544371Skarels case IP_RECVRETOPTS: 50644371Skarels OPTSET(INP_RECVRETOPTS); 50744371Skarels break; 50844371Skarels 50944371Skarels case IP_RECVDSTADDR: 51044371Skarels OPTSET(INP_RECVDSTADDR); 51144371Skarels break; 51244371Skarels } 51344371Skarels } 51444371Skarels break; 51544371Skarels #undef OPTSET 51644371Skarels 51754716Ssklower case IP_MULTICAST_IF: 51854716Ssklower case IP_MULTICAST_TTL: 51954716Ssklower case IP_MULTICAST_LOOP: 52054716Ssklower case IP_ADD_MEMBERSHIP: 52154716Ssklower case IP_DROP_MEMBERSHIP: 52254716Ssklower error = ip_setmoptions(optname, &inp->inp_moptions, m); 52354716Ssklower break; 52454716Ssklower 52551273Ssklower freeit: 52624814Skarels default: 52724814Skarels error = EINVAL; 52824814Skarels break; 52924814Skarels } 53044371Skarels if (m) 53144371Skarels (void)m_free(m); 53224814Skarels break; 53324814Skarels 53424814Skarels case PRCO_GETOPT: 53524814Skarels switch (optname) { 53624814Skarels case IP_OPTIONS: 53745014Skarels case IP_RETOPTS: 53844371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 53924814Skarels if (inp->inp_options) { 54044371Skarels m->m_len = inp->inp_options->m_len; 54124814Skarels bcopy(mtod(inp->inp_options, caddr_t), 54244371Skarels mtod(m, caddr_t), (unsigned)m->m_len); 54324814Skarels } else 54444371Skarels m->m_len = 0; 54524814Skarels break; 54644371Skarels 54744371Skarels case IP_TOS: 54844371Skarels case IP_TTL: 54944371Skarels case IP_RECVOPTS: 55044371Skarels case IP_RECVRETOPTS: 55144371Skarels case IP_RECVDSTADDR: 55244371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 55344371Skarels m->m_len = sizeof(int); 55445014Skarels switch (optname) { 55544371Skarels 55644371Skarels case IP_TOS: 55744371Skarels optval = inp->inp_ip.ip_tos; 55844371Skarels break; 55944371Skarels 56044371Skarels case IP_TTL: 56145567Ssklower optval = inp->inp_ip.ip_ttl; 56244371Skarels break; 56344371Skarels 56444371Skarels #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 56544371Skarels 56644371Skarels case IP_RECVOPTS: 56744371Skarels optval = OPTBIT(INP_RECVOPTS); 56844371Skarels break; 56944371Skarels 57044371Skarels case IP_RECVRETOPTS: 57144371Skarels optval = OPTBIT(INP_RECVRETOPTS); 57244371Skarels break; 57344371Skarels 57444371Skarels case IP_RECVDSTADDR: 57544371Skarels optval = OPTBIT(INP_RECVDSTADDR); 57644371Skarels break; 57744371Skarels } 57844371Skarels *mtod(m, int *) = optval; 57944371Skarels break; 58044371Skarels 58154716Ssklower case IP_MULTICAST_IF: 58254716Ssklower case IP_MULTICAST_TTL: 58354716Ssklower case IP_MULTICAST_LOOP: 58454716Ssklower case IP_ADD_MEMBERSHIP: 58554716Ssklower case IP_DROP_MEMBERSHIP: 58654716Ssklower error = ip_getmoptions(optname, inp->inp_moptions, mp); 58754716Ssklower break; 58854716Ssklower 58924814Skarels default: 59024814Skarels error = EINVAL; 59124814Skarels break; 59224814Skarels } 59324814Skarels break; 59424814Skarels } 59524814Skarels return (error); 59624814Skarels } 59724814Skarels 59824814Skarels /* 59926036Skarels * Set up IP options in pcb for insertion in output packets. 60026036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 60126036Skarels * with destination address if source routed. 60224814Skarels */ 60354716Ssklower int 60445014Skarels #ifdef notyet 60545014Skarels ip_pcbopts(optname, pcbopt, m) 60645014Skarels int optname; 60745014Skarels #else 60826036Skarels ip_pcbopts(pcbopt, m) 60945014Skarels #endif 61026036Skarels struct mbuf **pcbopt; 61126036Skarels register struct mbuf *m; 61224814Skarels { 61324814Skarels register cnt, optlen; 61424814Skarels register u_char *cp; 61524814Skarels u_char opt; 61624814Skarels 61724814Skarels /* turn off any old options */ 61826036Skarels if (*pcbopt) 61926385Skarels (void)m_free(*pcbopt); 62026036Skarels *pcbopt = 0; 62124814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 62224814Skarels /* 62324814Skarels * Only turning off any previous options. 62424814Skarels */ 62524814Skarels if (m) 62626385Skarels (void)m_free(m); 62724814Skarels return (0); 62824814Skarels } 62924814Skarels 63024814Skarels #ifndef vax 63124814Skarels if (m->m_len % sizeof(long)) 63224814Skarels goto bad; 63324814Skarels #endif 63424814Skarels /* 63524814Skarels * IP first-hop destination address will be stored before 63624814Skarels * actual options; move other options back 63724814Skarels * and clear it when none present. 63824814Skarels */ 63937318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 64024814Skarels goto bad; 64124814Skarels cnt = m->m_len; 64224814Skarels m->m_len += sizeof(struct in_addr); 64324814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 64426385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 64524814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 64624814Skarels 64724814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 64824814Skarels opt = cp[IPOPT_OPTVAL]; 64924814Skarels if (opt == IPOPT_EOL) 65024814Skarels break; 65124814Skarels if (opt == IPOPT_NOP) 65224814Skarels optlen = 1; 65324814Skarels else { 65424814Skarels optlen = cp[IPOPT_OLEN]; 65524814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 65624814Skarels goto bad; 65724814Skarels } 65824814Skarels switch (opt) { 65924814Skarels 66024814Skarels default: 66124814Skarels break; 66224814Skarels 66324814Skarels case IPOPT_LSRR: 66424814Skarels case IPOPT_SSRR: 66524814Skarels /* 66624814Skarels * user process specifies route as: 66724814Skarels * ->A->B->C->D 66824814Skarels * D must be our final destination (but we can't 66924814Skarels * check that since we may not have connected yet). 67024814Skarels * A is first hop destination, which doesn't appear in 67124814Skarels * actual IP option, but is stored before the options. 67224814Skarels */ 67324814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 67424814Skarels goto bad; 67524814Skarels m->m_len -= sizeof(struct in_addr); 67624814Skarels cnt -= sizeof(struct in_addr); 67724814Skarels optlen -= sizeof(struct in_addr); 67824814Skarels cp[IPOPT_OLEN] = optlen; 67924814Skarels /* 68024814Skarels * Move first hop before start of options. 68124814Skarels */ 68226385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 68324814Skarels sizeof(struct in_addr)); 68424814Skarels /* 68524814Skarels * Then copy rest of options back 68624814Skarels * to close up the deleted entry. 68724814Skarels */ 68826385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 68926385Skarels sizeof(struct in_addr)), 69026385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 69126385Skarels (unsigned)cnt + sizeof(struct in_addr)); 69224814Skarels break; 69324814Skarels } 69424814Skarels } 69537318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 69637318Skarels goto bad; 69726036Skarels *pcbopt = m; 69824814Skarels return (0); 69924814Skarels 70024814Skarels bad: 70126385Skarels (void)m_free(m); 70224814Skarels return (EINVAL); 70324814Skarels } 70454716Ssklower 70554716Ssklower /* 70654716Ssklower * Set the IP multicast options in response to user setsockopt(). 70754716Ssklower */ 70854716Ssklower int 70954716Ssklower ip_setmoptions(optname, imop, m) 71054716Ssklower int optname; 71154716Ssklower struct ip_moptions **imop; 71254716Ssklower struct mbuf *m; 71354716Ssklower { 71454716Ssklower register int error = 0; 71554716Ssklower u_char loop; 71654716Ssklower register int i; 71754716Ssklower struct in_addr addr; 71854716Ssklower register struct ip_mreq *mreq; 71954716Ssklower register struct ifnet *ifp; 72054716Ssklower register struct ip_moptions *imo = *imop; 72154716Ssklower struct route ro; 72254716Ssklower register struct sockaddr_in *dst; 72354716Ssklower 72454716Ssklower if (imo == NULL) { 72554716Ssklower /* 72654716Ssklower * No multicast option buffer attached to the pcb; 72754716Ssklower * allocate one and initialize to default values. 72854716Ssklower */ 72954716Ssklower imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, 73054716Ssklower M_WAITOK); 73154716Ssklower 73254716Ssklower if (imo == NULL) 73354716Ssklower return (ENOBUFS); 73454716Ssklower *imop = imo; 73554716Ssklower imo->imo_multicast_ifp = NULL; 73654716Ssklower imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 73754716Ssklower imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 73854716Ssklower imo->imo_num_memberships = 0; 73954716Ssklower } 74054716Ssklower 74154716Ssklower switch (optname) { 74254716Ssklower 74354716Ssklower case IP_MULTICAST_IF: 74454716Ssklower /* 74554716Ssklower * Select the interface for outgoing multicast packets. 74654716Ssklower */ 74754716Ssklower if (m == NULL || m->m_len != sizeof(struct in_addr)) { 74854716Ssklower error = EINVAL; 74954716Ssklower break; 75054716Ssklower } 75154716Ssklower addr = *(mtod(m, struct in_addr *)); 75254716Ssklower /* 75354716Ssklower * INADDR_ANY is used to remove a previous selection. 75454716Ssklower * When no interface is selected, a default one is 75554716Ssklower * chosen every time a multicast packet is sent. 75654716Ssklower */ 75754716Ssklower if (addr.s_addr == INADDR_ANY) { 75854716Ssklower imo->imo_multicast_ifp = NULL; 75954716Ssklower break; 76054716Ssklower } 76154716Ssklower /* 76254716Ssklower * The selected interface is identified by its local 76354716Ssklower * IP address. Find the interface and confirm that 76454716Ssklower * it supports multicasting. 76554716Ssklower */ 76654716Ssklower INADDR_TO_IFP(addr, ifp); 76754716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 76854716Ssklower error = EADDRNOTAVAIL; 76954716Ssklower break; 77054716Ssklower } 77154716Ssklower imo->imo_multicast_ifp = ifp; 77254716Ssklower break; 77354716Ssklower 77454716Ssklower case IP_MULTICAST_TTL: 77554716Ssklower /* 77654716Ssklower * Set the IP time-to-live for outgoing multicast packets. 77754716Ssklower */ 77854716Ssklower if (m == NULL || m->m_len != 1) { 77954716Ssklower error = EINVAL; 78054716Ssklower break; 78154716Ssklower } 78254716Ssklower imo->imo_multicast_ttl = *(mtod(m, u_char *)); 78354716Ssklower break; 78454716Ssklower 78554716Ssklower case IP_MULTICAST_LOOP: 78654716Ssklower /* 78754716Ssklower * Set the loopback flag for outgoing multicast packets. 78854716Ssklower * Must be zero or one. 78954716Ssklower */ 79054716Ssklower if (m == NULL || m->m_len != 1 || 79154716Ssklower (loop = *(mtod(m, u_char *))) > 1) { 79254716Ssklower error = EINVAL; 79354716Ssklower break; 79454716Ssklower } 79554716Ssklower imo->imo_multicast_loop = loop; 79654716Ssklower break; 79754716Ssklower 79854716Ssklower case IP_ADD_MEMBERSHIP: 79954716Ssklower /* 80054716Ssklower * Add a multicast group membership. 80154716Ssklower * Group must be a valid IP multicast address. 80254716Ssklower */ 80354716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 80454716Ssklower error = EINVAL; 80554716Ssklower break; 80654716Ssklower } 80754716Ssklower mreq = mtod(m, struct ip_mreq *); 80854716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 80954716Ssklower error = EINVAL; 81054716Ssklower break; 81154716Ssklower } 81254716Ssklower /* 81354716Ssklower * If no interface address was provided, use the interface of 81454716Ssklower * the route to the given multicast address. 81554716Ssklower */ 81654716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) { 81754716Ssklower ro.ro_rt = NULL; 81854716Ssklower dst = (struct sockaddr_in *)&ro.ro_dst; 81954716Ssklower dst->sin_len = sizeof(*dst); 82054716Ssklower dst->sin_family = AF_INET; 82154716Ssklower dst->sin_addr = mreq->imr_multiaddr; 82254716Ssklower rtalloc(&ro); 82354716Ssklower if (ro.ro_rt == NULL) { 82454716Ssklower error = EADDRNOTAVAIL; 82554716Ssklower break; 82654716Ssklower } 82754716Ssklower ifp = ro.ro_rt->rt_ifp; 82854716Ssklower rtfree(ro.ro_rt); 82954716Ssklower } 83054716Ssklower else { 83154716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 83254716Ssklower } 83354716Ssklower /* 83454716Ssklower * See if we found an interface, and confirm that it 83554716Ssklower * supports multicast. 83654716Ssklower */ 83754716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 83854716Ssklower error = EADDRNOTAVAIL; 83954716Ssklower break; 84054716Ssklower } 84154716Ssklower /* 84254716Ssklower * See if the membership already exists or if all the 84354716Ssklower * membership slots are full. 84454716Ssklower */ 84554716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 84654716Ssklower if (imo->imo_membership[i]->inm_ifp == ifp && 84754716Ssklower imo->imo_membership[i]->inm_addr.s_addr 84854716Ssklower == mreq->imr_multiaddr.s_addr) 84954716Ssklower break; 85054716Ssklower } 85154716Ssklower if (i < imo->imo_num_memberships) { 85254716Ssklower error = EADDRINUSE; 85354716Ssklower break; 85454716Ssklower } 85554716Ssklower if (i == IP_MAX_MEMBERSHIPS) { 85654716Ssklower error = ETOOMANYREFS; 85754716Ssklower break; 85854716Ssklower } 85954716Ssklower /* 86054716Ssklower * Everything looks good; add a new record to the multicast 86154716Ssklower * address list for the given interface. 86254716Ssklower */ 86354716Ssklower if ((imo->imo_membership[i] = 86454716Ssklower in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { 86554716Ssklower error = ENOBUFS; 86654716Ssklower break; 86754716Ssklower } 86854716Ssklower ++imo->imo_num_memberships; 86954716Ssklower break; 87054716Ssklower 87154716Ssklower case IP_DROP_MEMBERSHIP: 87254716Ssklower /* 87354716Ssklower * Drop a multicast group membership. 87454716Ssklower * Group must be a valid IP multicast address. 87554716Ssklower */ 87654716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 87754716Ssklower error = EINVAL; 87854716Ssklower break; 87954716Ssklower } 88054716Ssklower mreq = mtod(m, struct ip_mreq *); 88154716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 88254716Ssklower error = EINVAL; 88354716Ssklower break; 88454716Ssklower } 88554716Ssklower /* 88654716Ssklower * If an interface address was specified, get a pointer 88754716Ssklower * to its ifnet structure. 88854716Ssklower */ 88954716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) 89054716Ssklower ifp = NULL; 89154716Ssklower else { 89254716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 89354716Ssklower if (ifp == NULL) { 89454716Ssklower error = EADDRNOTAVAIL; 89554716Ssklower break; 89654716Ssklower } 89754716Ssklower } 89854716Ssklower /* 89954716Ssklower * Find the membership in the membership array. 90054716Ssklower */ 90154716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 90254716Ssklower if ((ifp == NULL || 90354716Ssklower imo->imo_membership[i]->inm_ifp == ifp) && 90454716Ssklower imo->imo_membership[i]->inm_addr.s_addr == 90554716Ssklower mreq->imr_multiaddr.s_addr) 90654716Ssklower break; 90754716Ssklower } 90854716Ssklower if (i == imo->imo_num_memberships) { 90954716Ssklower error = EADDRNOTAVAIL; 91054716Ssklower break; 91154716Ssklower } 91254716Ssklower /* 91354716Ssklower * Give up the multicast address record to which the 91454716Ssklower * membership points. 91554716Ssklower */ 91654716Ssklower in_delmulti(imo->imo_membership[i]); 91754716Ssklower /* 91854716Ssklower * Remove the gap in the membership array. 91954716Ssklower */ 92054716Ssklower for (++i; i < imo->imo_num_memberships; ++i) 92154716Ssklower imo->imo_membership[i-1] = imo->imo_membership[i]; 92254716Ssklower --imo->imo_num_memberships; 92354716Ssklower break; 92454716Ssklower 92554716Ssklower default: 92654716Ssklower error = EOPNOTSUPP; 92754716Ssklower break; 92854716Ssklower } 92954716Ssklower 93054716Ssklower /* 93154716Ssklower * If all options have default values, no need to keep the mbuf. 93254716Ssklower */ 93354716Ssklower if (imo->imo_multicast_ifp == NULL && 93454716Ssklower imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && 93554716Ssklower imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && 93654716Ssklower imo->imo_num_memberships == 0) { 93754716Ssklower free(*imop, M_IPMOPTS); 93854716Ssklower *imop = NULL; 93954716Ssklower } 94054716Ssklower 94154716Ssklower return (error); 94254716Ssklower } 94354716Ssklower 94454716Ssklower /* 94554716Ssklower * Return the IP multicast options in response to user getsockopt(). 94654716Ssklower */ 94754716Ssklower int 94854716Ssklower ip_getmoptions(optname, imo, mp) 94954716Ssklower int optname; 95054716Ssklower register struct ip_moptions *imo; 95154716Ssklower register struct mbuf **mp; 95254716Ssklower { 95354716Ssklower u_char *ttl; 95454716Ssklower u_char *loop; 95554716Ssklower struct in_addr *addr; 95654716Ssklower struct in_ifaddr *ia; 95754716Ssklower 95854716Ssklower *mp = m_get(M_WAIT, MT_SOOPTS); 95954716Ssklower 96054716Ssklower switch (optname) { 96154716Ssklower 96254716Ssklower case IP_MULTICAST_IF: 96354716Ssklower addr = mtod(*mp, struct in_addr *); 96454716Ssklower (*mp)->m_len = sizeof(struct in_addr); 96554716Ssklower if (imo == NULL || imo->imo_multicast_ifp == NULL) 96654716Ssklower addr->s_addr = INADDR_ANY; 96754716Ssklower else { 96854716Ssklower IFP_TO_IA(imo->imo_multicast_ifp, ia); 96954716Ssklower addr->s_addr = (ia == NULL) ? INADDR_ANY 97054716Ssklower : IA_SIN(ia)->sin_addr.s_addr; 97154716Ssklower } 97254716Ssklower return (0); 97354716Ssklower 97454716Ssklower case IP_MULTICAST_TTL: 97554716Ssklower ttl = mtod(*mp, u_char *); 97654716Ssklower (*mp)->m_len = 1; 97754716Ssklower *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL 97854716Ssklower : imo->imo_multicast_ttl; 97954716Ssklower return (0); 98054716Ssklower 98154716Ssklower case IP_MULTICAST_LOOP: 98254716Ssklower loop = mtod(*mp, u_char *); 98354716Ssklower (*mp)->m_len = 1; 98454716Ssklower *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP 98554716Ssklower : imo->imo_multicast_loop; 98654716Ssklower return (0); 98754716Ssklower 98854716Ssklower default: 98954716Ssklower return (EOPNOTSUPP); 99054716Ssklower } 99154716Ssklower } 99254716Ssklower 99354716Ssklower /* 99454716Ssklower * Discard the IP multicast options. 99554716Ssklower */ 99654716Ssklower void 99754716Ssklower ip_freemoptions(imo) 99854716Ssklower register struct ip_moptions *imo; 99954716Ssklower { 100054716Ssklower register int i; 100154716Ssklower 100254716Ssklower if (imo != NULL) { 100354716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) 100454716Ssklower in_delmulti(imo->imo_membership[i]); 100554716Ssklower free(imo, M_IPMOPTS); 100654716Ssklower } 100754716Ssklower } 100854716Ssklower 100954716Ssklower /* 101054716Ssklower * Routine called from ip_output() to loop back a copy of an IP multicast 101154716Ssklower * packet to the input queue of a specified interface. Note that this 101254716Ssklower * calls the output routine of the loopback "driver", but with an interface 101354716Ssklower * pointer that might NOT be &loif -- easier than replicating that code here. 101454716Ssklower */ 101554716Ssklower static void 101654716Ssklower ip_mloopback(ifp, m, dst) 101754716Ssklower struct ifnet *ifp; 101854716Ssklower register struct mbuf *m; 101954716Ssklower register struct sockaddr_in *dst; 102054716Ssklower { 102154716Ssklower register struct ip *ip; 102254716Ssklower struct mbuf *copym; 102354716Ssklower 102454716Ssklower copym = m_copy(m, 0, M_COPYALL); 102554716Ssklower if (copym != NULL) { 102654716Ssklower /* 102754716Ssklower * We don't bother to fragment if the IP length is greater 102854716Ssklower * than the interface's MTU. Can this possibly matter? 102954716Ssklower */ 103054716Ssklower ip = mtod(copym, struct ip *); 103154716Ssklower ip->ip_len = htons((u_short)ip->ip_len); 103254716Ssklower ip->ip_off = htons((u_short)ip->ip_off); 103354716Ssklower ip->ip_sum = 0; 103454716Ssklower ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); 103554716Ssklower (void) looutput(ifp, copym, (struct sockaddr *)dst); 103654716Ssklower } 103754716Ssklower } 1038