root/arch/um/drivers/umcast_user.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. new_addr
  2. umcast_user_init
  3. umcast_remove
  4. umcast_open
  5. umcast_close
  6. umcast_user_write

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * user-mode-linux networking multicast transport
   4  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   5  * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
   6  *
   7  * based on the existing uml-networking code, which is
   8  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
   9  * James Leu (jleu@mindspring.net).
  10  * Copyright (C) 2001 by various other people who didn't put their name here.
  11  *
  12  *
  13  */
  14 
  15 #include <unistd.h>
  16 #include <errno.h>
  17 #include <netinet/in.h>
  18 #include "umcast.h"
  19 #include <net_user.h>
  20 #include <um_malloc.h>
  21 
  22 static struct sockaddr_in *new_addr(char *addr, unsigned short port)
  23 {
  24         struct sockaddr_in *sin;
  25 
  26         sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
  27         if (sin == NULL) {
  28                 printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
  29                        "failed\n");
  30                 return NULL;
  31         }
  32         sin->sin_family = AF_INET;
  33         if (addr)
  34                 sin->sin_addr.s_addr = in_aton(addr);
  35         else
  36                 sin->sin_addr.s_addr = INADDR_ANY;
  37         sin->sin_port = htons(port);
  38         return sin;
  39 }
  40 
  41 static int umcast_user_init(void *data, void *dev)
  42 {
  43         struct umcast_data *pri = data;
  44 
  45         pri->remote_addr = new_addr(pri->addr, pri->rport);
  46         if (pri->unicast)
  47                 pri->listen_addr = new_addr(NULL, pri->lport);
  48         else
  49                 pri->listen_addr = pri->remote_addr;
  50         pri->dev = dev;
  51         return 0;
  52 }
  53 
  54 static void umcast_remove(void *data)
  55 {
  56         struct umcast_data *pri = data;
  57 
  58         kfree(pri->listen_addr);
  59         if (pri->unicast)
  60                 kfree(pri->remote_addr);
  61         pri->listen_addr = pri->remote_addr = NULL;
  62 }
  63 
  64 static int umcast_open(void *data)
  65 {
  66         struct umcast_data *pri = data;
  67         struct sockaddr_in *lsin = pri->listen_addr;
  68         struct sockaddr_in *rsin = pri->remote_addr;
  69         struct ip_mreq mreq;
  70         int fd, yes = 1, err = -EINVAL;
  71 
  72 
  73         if ((!pri->unicast && lsin->sin_addr.s_addr == 0) ||
  74             (rsin->sin_addr.s_addr == 0) ||
  75             (lsin->sin_port == 0) || (rsin->sin_port == 0))
  76                 goto out;
  77 
  78         fd = socket(AF_INET, SOCK_DGRAM, 0);
  79 
  80         if (fd < 0) {
  81                 err = -errno;
  82                 printk(UM_KERN_ERR "umcast_open : data socket failed, "
  83                        "errno = %d\n", errno);
  84                 goto out;
  85         }
  86 
  87         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
  88                 err = -errno;
  89                 printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
  90                        "errno = %d\n", errno);
  91                 goto out_close;
  92         }
  93 
  94         if (!pri->unicast) {
  95                 /* set ttl according to config */
  96                 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
  97                                sizeof(pri->ttl)) < 0) {
  98                         err = -errno;
  99                         printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
 100                                "failed, error = %d\n", errno);
 101                         goto out_close;
 102                 }
 103 
 104                 /* set LOOP, so data does get fed back to local sockets */
 105                 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP,
 106                                &yes, sizeof(yes)) < 0) {
 107                         err = -errno;
 108                         printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
 109                                "failed, error = %d\n", errno);
 110                         goto out_close;
 111                 }
 112         }
 113 
 114         /* bind socket to the address */
 115         if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
 116                 err = -errno;
 117                 printk(UM_KERN_ERR "umcast_open : data bind failed, "
 118                        "errno = %d\n", errno);
 119                 goto out_close;
 120         }
 121 
 122         if (!pri->unicast) {
 123                 /* subscribe to the multicast group */
 124                 mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
 125                 mreq.imr_interface.s_addr = 0;
 126                 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
 127                                &mreq, sizeof(mreq)) < 0) {
 128                         err = -errno;
 129                         printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP "
 130                                "failed, error = %d\n", errno);
 131                         printk(UM_KERN_ERR "There appears not to be a "
 132                                "multicast-capable network interface on the "
 133                                "host.\n");
 134                         printk(UM_KERN_ERR "eth0 should be configured in order "
 135                                "to use the multicast transport.\n");
 136                         goto out_close;
 137                 }
 138         }
 139 
 140         return fd;
 141 
 142  out_close:
 143         close(fd);
 144  out:
 145         return err;
 146 }
 147 
 148 static void umcast_close(int fd, void *data)
 149 {
 150         struct umcast_data *pri = data;
 151 
 152         if (!pri->unicast) {
 153                 struct ip_mreq mreq;
 154                 struct sockaddr_in *lsin = pri->listen_addr;
 155 
 156                 mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
 157                 mreq.imr_interface.s_addr = 0;
 158                 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
 159                                &mreq, sizeof(mreq)) < 0) {
 160                         printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP "
 161                                "failed, error = %d\n", errno);
 162                 }
 163         }
 164 
 165         close(fd);
 166 }
 167 
 168 int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
 169 {
 170         struct sockaddr_in *data_addr = pri->remote_addr;
 171 
 172         return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
 173 }
 174 
 175 const struct net_user_info umcast_user_info = {
 176         .init   = umcast_user_init,
 177         .open   = umcast_open,
 178         .close  = umcast_close,
 179         .remove = umcast_remove,
 180         .add_address    = NULL,
 181         .delete_address = NULL,
 182         .mtu    = ETH_MAX_PACKET,
 183         .max_packet     = ETH_MAX_PACKET + ETH_HEADER_OTHER,
 184 };

/* [<][>][^][v][top][bottom][index][help] */