105105 (VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \
106106 VIRTIO_F_NOTIFY_ON_EMPTY)
107107
108+ #define ETHER_IS_MULTICAST (addr ) (*(addr) & 0x01) /* is address mcast/bcast? */
109+
108110/*
109111 * PCI config-space "registers"
110112 */
111113struct virtio_net_config {
112114 uint8_t mac [6 ];
113115 uint16_t status ;
116+ int mac_provided ;
114117} __packed ;
115118
116119/*
@@ -253,6 +256,16 @@ vmn_create(struct pci_vtnet_softc *sc)
253256 return ;
254257 }
255258
259+ if (sc -> vsc_config .mac_provided ) {
260+ char mac_str [18 ];
261+
262+ sprintf (mac_str , "%02x:%02x:%02x:%02x:%02x:%02x" ,
263+ sc -> vsc_config .mac [0 ], sc -> vsc_config .mac [1 ], sc -> vsc_config .mac [2 ],
264+ sc -> vsc_config .mac [3 ], sc -> vsc_config .mac [4 ], sc -> vsc_config .mac [5 ]);
265+
266+ xpc_dictionary_set_string (interface_param , vmnet_mac_address_key , mac_str );
267+ }
268+
256269 if (sscanf (xpc_dictionary_get_string (interface_param ,
257270 vmnet_mac_address_key ),
258271 "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" ,
@@ -697,10 +710,28 @@ pci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq)
697710#endif
698711
699712static int
700- pci_vtnet_init (struct pci_devinst * pi , UNUSED char * opts )
713+ pci_vtnet_parsemac (char * mac_str , uint8_t * mac_addr )
714+ {
715+ struct ether_addr * ea ;
716+ char zero_addr [ETHER_ADDR_LEN ] = { 0 , 0 , 0 , 0 , 0 , 0 };
717+
718+ ea = ether_aton (mac_str );
719+
720+ if (ea == NULL || ETHER_IS_MULTICAST (ea -> octet ) ||
721+ memcmp (ea -> octet , zero_addr , ETHER_ADDR_LEN ) == 0 ) {
722+ fprintf (stderr , "Invalid MAC address: %s\n" , mac_str );
723+ return (EINVAL );
724+ } else {
725+ memcpy (mac_addr , ea -> octet , ETHER_ADDR_LEN );
726+ }
727+
728+ return (0 );
729+ }
730+
731+ static int
732+ pci_vtnet_init (struct pci_devinst * pi , char * opts )
701733{
702734 struct pci_vtnet_softc * sc ;
703- int mac_provided ;
704735
705736 sc = calloc (1 , sizeof (struct pci_vtnet_softc ));
706737
@@ -718,11 +749,24 @@ pci_vtnet_init(struct pci_devinst *pi, UNUSED char *opts)
718749 sc -> vsc_queues [VTNET_CTLQ ].vq_notify = pci_vtnet_ping_ctlq ;
719750#endif
720751
721- /*
722- * Attempt to open the tap device and read the MAC address
723- * if specified
724- */
725- mac_provided = 0 ;
752+ if (opts != NULL ) {
753+ int err ;
754+ char * mac_str ;
755+ char * tmp_str ;
756+
757+ mac_str = strdup (opts );
758+ (void ) strsep (& mac_str , "," );
759+
760+ tmp_str = strsep (& mac_str , "=" );
761+
762+ if (!strcmp (tmp_str , "mac" ) && mac_str != NULL ) {
763+ err = pci_vtnet_parsemac (mac_str , sc -> vsc_config .mac );
764+ if (err != 0 ) {
765+ return (err );
766+ }
767+ sc -> vsc_config .mac_provided = 1 ;
768+ }
769+ }
726770
727771 if (vmn_create (sc ) == -1 ) {
728772 return (-1 );
0 commit comments