diff options
Diffstat (limited to 'net/phonet/af_phonet.c')
-rw-r--r-- | net/phonet/af_phonet.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index ba54d53020ff..e6771d3961cf 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c | |||
@@ -99,6 +99,101 @@ static struct net_proto_family phonet_proto_family = { | |||
99 | .owner = THIS_MODULE, | 99 | .owner = THIS_MODULE, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | /* | ||
103 | * Prepends an ISI header and sends a datagram. | ||
104 | */ | ||
105 | static int pn_send(struct sk_buff *skb, struct net_device *dev, | ||
106 | u16 dst, u16 src, u8 res) | ||
107 | { | ||
108 | struct phonethdr *ph; | ||
109 | int err; | ||
110 | |||
111 | if (skb->len + 2 > 0xffff) { | ||
112 | /* Phonet length field would overflow */ | ||
113 | err = -EMSGSIZE; | ||
114 | goto drop; | ||
115 | } | ||
116 | |||
117 | skb_reset_transport_header(skb); | ||
118 | WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */ | ||
119 | skb_push(skb, sizeof(struct phonethdr)); | ||
120 | skb_reset_network_header(skb); | ||
121 | ph = pn_hdr(skb); | ||
122 | ph->pn_rdev = pn_dev(dst); | ||
123 | ph->pn_sdev = pn_dev(src); | ||
124 | ph->pn_res = res; | ||
125 | ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph)); | ||
126 | ph->pn_robj = pn_obj(dst); | ||
127 | ph->pn_sobj = pn_obj(src); | ||
128 | |||
129 | skb->protocol = htons(ETH_P_PHONET); | ||
130 | skb->priority = 0; | ||
131 | skb->dev = dev; | ||
132 | |||
133 | if (pn_addr(src) == pn_addr(dst)) { | ||
134 | skb_reset_mac_header(skb); | ||
135 | skb->pkt_type = PACKET_LOOPBACK; | ||
136 | skb_orphan(skb); | ||
137 | netif_rx_ni(skb); | ||
138 | err = 0; | ||
139 | } else { | ||
140 | err = dev_hard_header(skb, dev, ntohs(skb->protocol), | ||
141 | NULL, NULL, skb->len); | ||
142 | if (err < 0) { | ||
143 | err = -EHOSTUNREACH; | ||
144 | goto drop; | ||
145 | } | ||
146 | err = dev_queue_xmit(skb); | ||
147 | } | ||
148 | |||
149 | return err; | ||
150 | drop: | ||
151 | kfree_skb(skb); | ||
152 | return err; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Create a Phonet header for the skb and send it out. Returns | ||
157 | * non-zero error code if failed. The skb is freed then. | ||
158 | */ | ||
159 | int pn_skb_send(struct sock *sk, struct sk_buff *skb, | ||
160 | const struct sockaddr_pn *target) | ||
161 | { | ||
162 | struct net_device *dev; | ||
163 | struct pn_sock *pn = pn_sk(sk); | ||
164 | int err; | ||
165 | u16 src; | ||
166 | u8 daddr = pn_sockaddr_get_addr(target), saddr = PN_NO_ADDR; | ||
167 | |||
168 | err = -EHOSTUNREACH; | ||
169 | if (sk->sk_bound_dev_if) | ||
170 | dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); | ||
171 | else | ||
172 | dev = phonet_device_get(sock_net(sk)); | ||
173 | if (!dev || !(dev->flags & IFF_UP)) | ||
174 | goto drop; | ||
175 | |||
176 | saddr = phonet_address_get(dev, daddr); | ||
177 | if (saddr == PN_NO_ADDR) | ||
178 | goto drop; | ||
179 | |||
180 | src = pn->sobject; | ||
181 | if (!pn_addr(src)) | ||
182 | src = pn_object(saddr, pn_obj(src)); | ||
183 | |||
184 | err = pn_send(skb, dev, pn_sockaddr_get_object(target), | ||
185 | src, pn_sockaddr_get_resource(target)); | ||
186 | dev_put(dev); | ||
187 | return err; | ||
188 | |||
189 | drop: | ||
190 | kfree_skb(skb); | ||
191 | if (dev) | ||
192 | dev_put(dev); | ||
193 | return err; | ||
194 | } | ||
195 | EXPORT_SYMBOL(pn_skb_send); | ||
196 | |||
102 | /* packet type functions */ | 197 | /* packet type functions */ |
103 | 198 | ||
104 | /* | 199 | /* |
@@ -226,11 +321,22 @@ static int __init phonet_init(void) | |||
226 | phonet_device_init(); | 321 | phonet_device_init(); |
227 | dev_add_pack(&phonet_packet_type); | 322 | dev_add_pack(&phonet_packet_type); |
228 | phonet_netlink_register(); | 323 | phonet_netlink_register(); |
324 | |||
325 | err = isi_register(); | ||
326 | if (err) | ||
327 | goto err; | ||
229 | return 0; | 328 | return 0; |
329 | |||
330 | err: | ||
331 | sock_unregister(AF_PHONET); | ||
332 | dev_remove_pack(&phonet_packet_type); | ||
333 | phonet_device_exit(); | ||
334 | return err; | ||
230 | } | 335 | } |
231 | 336 | ||
232 | static void __exit phonet_exit(void) | 337 | static void __exit phonet_exit(void) |
233 | { | 338 | { |
339 | isi_unregister(); | ||
234 | sock_unregister(AF_PHONET); | 340 | sock_unregister(AF_PHONET); |
235 | dev_remove_pack(&phonet_packet_type); | 341 | dev_remove_pack(&phonet_packet_type); |
236 | phonet_device_exit(); | 342 | phonet_device_exit(); |